[net.lang.c] Preprocessor Trickery

whm@arizona.UUCP (Bill Mitchell) (06/26/84)

I need a way to form variable names using cpp macros.  For example, I'd
like a macro X(y), which might expand X(foo) into Xfoo.  It so happens
that

	#define X(y) X/**/y
	X(foo)

works on 4.xbsd and on V7.  This apparently because cpp considers
	int z/**/z;
to be
	int zz;

Is there some proper way to achieve the same effect without relying on
this "feature" of cpp and thus retain some hope of portability?

					Thanks,
					Bill Mitchell
					whm.arizona@csnet-relay
					{noao,mcnc,utah-cs}!arizona!whm

gwyn@BRL-VLD.ARPA (06/28/84)

From:      Doug Gwyn (VLD/VMB) <gwyn@BRL-VLD.ARPA>

At USENIX, the word was that there really is no way to concatenate
strings using the C preprocessor in a portable way, but the ANSI
committee is considering how this might be done.  The tricks that
work with the Reiser preprocessor do not necessarily work elsewhere.

ron@brl-vgr.ARPA (Ron Natalie <ron>) (06/28/84)

The behaviour is wrong.  According to the manual a comment is supposed to
be syntactically like white space.  The C standards people are suggesting
that a new character ('#') be used by the preprocessor to do the same thing
that /**/ is used for.

-Ron

marcus@pyuxt.UUCP (M. G. Hand) (06/29/84)

Distasteful as it may be, the  X/**/y feature is well documented in the
source of cpp by John Reiser, and is portable at least as far as System V.
		Marcus Hand  (pyuxt!marcus)

jpl@allegra.UUCP (John P. Linderman) (06/29/84)

I expected to see a hail of responses to this item, but since a few
days have gone by, and the only response has been in support of X/**/y,
the following ought to see the light of day:

#define QUOTE(X) X
#define MAKENAME(Y) QUOTE(X)Y
#define CAT(X,Y) QUOTE(X)Y

MAKENAME(lax)
CAT(X,pertsystems)

As long as macros are supported, this mechanism will work; no tricky
stuff.  To give credit where it is due, I think I first saw the
QUOTE macro used by Mike Bianchi, for quite different reasons.
It's a useful addition to one's bag of tricks.

John P. Linderman  Department of Macro Biology  allegra!jpl

rgh@inmet.UUCP (06/30/84)

#R:arizona:-1236100:inmet:5000019:000:403
inmet!rgh    Jun 28 14:01:00 1984

There's no portable way to use C #define's to introduce new tokens into
a program, since macro replacement is defined in terms of token strings
in K&R [C RefMan 12.1].  This issue -- character string vs. token string
macros -- came up at the most recent C ANSI standards committee meeting,
and the token string viewpoint prevailed. 

			    Randy Hudson
			    {harpo, ihnp4, decvax!cca!ima} !inmet!rgh

henry@utzoo.UUCP (Henry Spencer) (07/01/84)

> Distasteful as it may be, the  X/**/y feature is well documented in the
> source of cpp by John Reiser, and is portable at least as far as System V.

Since it's documented in the source, that means it's effectively entirely
undocumented as far as binary licensees are concerned.  Furthermore, one
finds the documentation in the source only by accident, since that's not
exactly the first place one looks for documentation.  And it is *not*
portable to most non-Bell-derived compilers, since most of their authors
didn't have access to the cpp sources.

The ANSI C standards effort is standardizing the preprocessor facilities
as part of the language.  "X/**/y" is *not* allowed in the standard.  "If
you want a general-purpose macro processor, use m4!"
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry

bet@ecsvax.UUCP (07/02/84)

Someone made a comment earlier that seems to have been ignored by many,
that efforts like X/**/Y and the QUOTE macro *aren't* guaranteed to be
portable, and further that *no* mechanism is guaranteed to be portable,
since in theory the cpp functionality is defined in terms of *tokens*.
That is to say, the standard, *required* behavior of cpp could be produced
by code between the lexical analyzer and the parser. Composite token
creation can only really be expected to show up when cpp is a distinct
pass of the compiler, producing "clear", preprocessed C as an intermediate
step, which then undergoes another lexical analysis. In fact this
is not the only way that compilers are created -- small, fast single pass
compilers for micros, to keep the amount of overlaying required down,
sometimes build the functionality of cpp *into* the compiler. A second
lexical analysis is legitimately considered an unnecessary waste of
time and space. Let us keep in mind that one of the strongest aspects
of C is how good a language it is for small systems.

					Bennett Todd
					...{decvax,ihnp4,akgua}!mcnc!ecsvax!bet

ado@elsie.UUCP (07/11/84)

>	For concatenating strings at preprocessor time, try this:
>
>	#define Ident(xxx) xxx
>
>	#define concat(a,b) Ident(a)b
>
>	It should always work. . .

"Always"?  How about if either "a" or "b" is "__LINE__"?
Try typing this to see what happens:
	cc -E -
	#define Ident(xxx) xxx
	#define concat(a,b) Ident(a)b
	__LINE__
	concat(__LINE__,__LINE__)

--
	...decvax!allegra!umcp-cs!elsie!ado	(301) 496-5688
	(the DEC and VAX in decvax are Digital Equipment Corporation trademarks)

jwp@sdchema.UUCP (07/13/84)

...!elsie!ado:

	>Try typing this to see what happens:
	>	cc -E -
	>	#define Ident(xxx) xxx
	>	#define concat(a,b) Ident(a)b
	>	__LINE__
	>	concat(__LINE__,__LINE__)

"concat(__LINE__,__LINE__)" gives "__LINE____LINE__"
"concat(__LINE__, __LINE__)" gives, e.g.,  "3 3"

For that matter:	"concat(this,that)" results in "thisthat"
			"concat(this, that)" results in "this that"

Defining "concat(a, b)" instead of "concat(a,b)" doesn't, however, seem to
make a difference.  It *is* interesting behavior.  And also reinforces my
general feelings that:  (a) relying on the preprocessor to do too much for you
is foolish, and (b) being very clever is a really fun way to screw up those
that follow you (or yourself when you have to go back to the miserable thing
two years later and have forgotten how terribly clever you were), especially
when you follow the customary C commenting conventions.

				John Pierce, Chemistry, UC San Diego
				sdcsvax!sdchema!jwp

jim@ism780b.UUCP (08/02/84)

#R:elsie:-101400:ism780b:25500010:000:1888
ism780b!jim    Jul 17 21:58:00 1984

>
>         >Try typing this to see what happens:
>         >       cc -E -
>         >       #define Ident(xxx) xxx
>         >       #define concat(a,b) Ident(a)b
>         >       __LINE__
>         >       concat(__LINE__,__LINE__)
>
> "concat(__LINE__,__LINE__)" gives "__LINE____LINE__"
> "concat(__LINE__, __LINE__)" gives, e.g.,  "3 3"

Not with a Reiser cpp (this is just one of the hundreds of bugs;
I too rolled my own).

>For that matter:        "concat(this,that)" results in "thisthat"
>                        "concat(this, that)" results in "this that"

Easy to explain: the arguments to a macro consist of the text between
parens and commas (not nested within parens), including any white space.
Thus, you concatenated "this" with " that".  The problem is that there
is no formal documentation of cpp.

> Defining "concat(a, b)" instead of "concat(a,b)" doesn't, however, seem to
> make a difference.

Of course, since "a" and "b" are just tokens to be replaced in the replacement
text.

> It *is* interesting behavior.

Not very.

> And also reinforces my
> general feelings that:  (a) relying on the preprocessor to do too much for you
> is foolish, and (b) being very clever is a really fun way to screw up those
that follow you (or yourself when you have to go back to the miserable thing
two years later and have forgotten how terribly clever you were), especially
when you follow the customary C commenting conventions.

Definitely true given that it is undocumented, although understandable when
the only alternative is m4.  When defining a macro which can be tucked away
in a common include file with plenty of comments can allow you to write
far more readable and modifiable code elsewhere, then it may not be so
foolish.  However, if it is just used to support another favorite hack,
then the cause is lost anyway.

-- Jim Balter, INTERACTIVE Systems (ima!jim)