[net.lang.c] Can #define `token-string' be empty?

shields@acf4.UUCP (David Shields) (02/14/85)

Is
	#define	X
valid, i.e., can the `token-string' mentioned on page 207 of K&R be empty?

robert@gitpyr.UUCP (Robert Viduya) (02/17/85)

><
Posted from  shields@acf4.UUCP (David Shields)
> Is
> 	#define	X
> valid, i.e., can the `token-string' mentioned on page 207 of K&R be empty?

Under 4.2BSD it is.  I would suspect it to be true under any version of
cpp, however I'm not sure.

			robert
-- 
Robert Viduya
Georgia Institute of Technology

...!{akgua,allegra,amd,hplabs,ihnp4,masscomp,ut-ngp}!gatech!gitpyr!robert
...!{rlgvax,sb1,uf-cgrl,unmvax,ut-sally}!gatech!gitpyr!robert

mgh@hou5h.UUCP (Marcus Hand) (02/19/85)

> Is
>	#define x
> valid?

Oh yes, very much so.  It is very useful for controlling conditional
compilation, eg the inclusion or exclusion of debugging and trace code:

	#define	DEBUG
	.
	.
	.
	#ifdef DEBUG
		fprintf(stderr,"Variable is %d\n",Variable);
	#endif

It can also be set on the compilation command line (and inside makefiles
of course) like this:

	cc .... -DDEBUG ....

	Hope this helps,

		marcus hand

larry@cci-bdc.UUCP (Larry DeLuca) (02/19/85)

> Is
> 	#define	X
> valid, i.e., can the `token-string' mentioned on page 207 of K&R be empty?

Yes.  the default value of X is 1.

					larry...


-- 
uucp:  ..mit-eddie!cybvax0!cci-bdc!larry

arpa:  henrik@mit-mc.ARPA

This mind intentionally left blank.

boris@sftri.UUCP (B.Altman) (02/20/85)

> Is
> 	#define	X
> valid, i.e., can the `token-string' mentioned on page 207 of K&R be empty?

According to AT&T cpp the answer is yes.
According to the latest ANSI C draft the answer is yes also.

				Boris Altman
				ATT Bell Labs Summit NJ
				{ucbvax,ihnp4,allegra}!attunix!boris

peterc@ecr.UUCP (Peter Curran) (02/21/85)

Yes, in all versions of C I have used, the token string can be empty.
However, some version have a bug, which may or not be serious, depending
on the application.  The bug is in V7 UNIX, and variants derived from it.

The problem is that if you #undef a variable that has no value, the
preprocessor symbol table gets screwed up, and actually leaves the
symbol defined, but with its name pointer pointing into the 'stdio'
buffer of the source file.  Under various circumstances, if another
symbol occurs at the same place in the buffer (i.e. if it occurs at
the same place in the file, modulo the block size), the preprocessor
will fail to recognize that symbol, and if it should be preprocessed,
it gets passed through to the main compiler.

No doubt most users will not encounter the problem, because using symbols
with no value is unusual, and using #undef is probably even less common.
Even if you hit the problem, slight modifications to the source will
move things in the buffer and mask the problem.  We have some coding
conventions that call for both of these quite regularly, so it is
a nuisance.  Fortunately, we have found that in all cases where
we used an empty value, the value ';' would do just as well.

I no longer have access to UNIX source, but some time ago we discovered
the cause of the problem.  The function that handles undef's expects
a char parameter that tells it what to do.  The value for undef is
defined as 0xFF, which the author expected to be sign-extended, and
tested for as 'mode < 0'.  Of course, most machines do not sign-extend,
and even those that do treat 0xFF as an integer, not a character, and
don't sign-extend it.  Anyone with access to the preprocessor source
may want to fix this, and perhaps post a better description of the
solution than I can give.

gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) (02/21/85)

> 	cc .... -DDEBUG ....

Of course in this case DEBUG is defined to be "1", not empty.

gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) (02/21/85)

> > 	#define	X
> 
> Yes.  the default value of X is 1.

Not in this usage; it is empty ("").

tim@cmu-cs-k.ARPA (Tim Maroney) (02/21/85)

> > Is
> > 	#define	X
> > valid, i.e., can the `token-string' mentioned on page 207 of K&R be empty?
>
> Yes.  the default value of X is 1.
>
>					larry...

Wrong.  The default value of X is nothing.  Any instances of the token X
will be removed from the source file before parsing.  This is frequently
used to make include files do double duty.  At the start of the include
file, put

#ifndef EXTERN
#define EXTERN extern
#endif

Then the include file should contain declaratons of this form:

EXTERN int global_int;
EXTERN struct marsupial *wombat;

Including the file normally causes these to be external declarations, that
is, no space is allocated for the variables.  Then, in the source file where
you want to actually have the variables' storage allocated, you just say

#define EXTERN
#include "whatever.h"
-=-
Tim Maroney, Carnegie-Mellon University Computation Center
ARPA:	Tim.Maroney@CMU-CS-K	uucp:	seismo!cmu-cs-k!tim
CompuServe:	74176,1360	audio:	shout "Hey, Tim!"

"Remember all ye that existence is pure joy; that all the sorrows are
but as shadows; they pass & are done; but there is that which remains."
Liber AL, II:9.

rpw3@redwood.UUCP (Rob Warnock) (02/22/85)

+---------------
| > Is
| > 	#define	X
| > valid, i.e., can the `token-string' mentioned on page 207 of K&R be empty?
| Yes.  the default value of X is 1.  |	larry...
| uucp:  ..mit-eddie!cybvax0!cci-bdc!larry | arpa:  henrik@mit-mc.ARPA
+---------------

Well, almost, Larry. There is no "default" for a "#define"; the empty
token-string is perfectly legal. See K & R page 87 for an example of an
empty token-string (the "then" macro).

You are probably thinking of the case of a symbol defined on the "cc"
command line with no value, as in "cc -DFOO bar.c" which defines "FOO"
to be 1. But if it is given a value the value is used, even if empty,
as in "cc -DFOO= bar.c" which defines "FOO" to be empty, not 1.


Rob Warnock
Systems Architecture Consultant

UUCP:	{ihnp4,ucbvax!dual}!fortune!redwood!rpw3
DDD:	(415)572-2607
USPS:	510 Trinidad Lane, Foster City, CA  94404

rwl@uvacs.UUCP (Ray Lubinsky) (02/24/85)

> > Is
> > 	#define	X
> > valid, i.e., can the `token-string' mentioned on page 207 of K&R be empty?
> 
> Yes.  the default value of X is 1.
> 
> 					larry...

   This is also the way I've understood #define, but I made a little program
just to test it out.  Fact is, X is not literally given a default value of 1.
You can really only say that it has the value of "defined" as far as the
pre-processor (/lib/cpp) is concerned.  Consider the following C program which
I fed to /lib/cpp :

C source:				Output from preprocessor:
===================================	=======================================
#include <stdio.h>			...  (stuff from the include file here)
#define	X

main()					main()
{					{
	printf("This is X: %d\n",X);		printf("This is X: %d\n",);
}					}

   Clearly, X was not considered to be 1 (or anything), and when I attempted to
used the test  #if X == 1  , the preprocessor complained of syntax error (since
it translated the line into  #if  == 1  .

   Empty #define's should be used only in connection with #ifdef and #ifndef
tests.  Otherwise they have little usefulness.

------------------------------------------------------------------------------

Ray Lubinsky		     University of Virginia, Dept. of Computer Science
			     uucp: decvax!mcnc!ncsu!uvacs!rwl

--------------  The mind is buddha.  The mind is not buddha.  ----------------

boris@sftri.UUCP (B.Altman) (02/25/85)

> 
> #ifndef EXTERN
> #define EXTERN extern
> #endif
> 
> Then the include file should contain declaratons of this form:
> 
> EXTERN int global_int;
> EXTERN struct marsupial *wombat;
> 
> Including the file normally causes these to be external declarations, that
> is, no space is allocated for the variables.  Then, in the source file where
> you want to actually have the variables' storage allocated, you just say
> 
> #define EXTERN
> #include "whatever.h"

This is not necessary on System V release 2 C compiler. You can omit extern
everywhere. ld will be able to handle those constructs.

			Boris Altman
			{ucbvax,ihnp4}!attunix!boris

jc@mit-athena.UUCP (John Chambers) (02/25/85)

+---------------
| > Is
| > 	#define	X
| > valid, i.e., can the `token-string' mentioned on page 207 of K&R be empty?
| Yes.  the default value of X is 1.  |	larry...
| uucp:  ..mit-eddie!cybvax0!cci-bdc!larry | arpa:  henrik@mit-mc.ARPA
+---------------

Gee, I hope not.  This would undercut the following:
  #define then
  #define begin {
  #define end   }
  ...
   if (foo) then begin
     ...
     end
   else begin
     ...
   end
Now, maybe you like C's syntax.  I know I prefer it to the wordier
form in this example.  But there's really no reason other than taste
(about which there is an ancient Roman saying; I betcha you know it)
to object to this.  I have even used tricks like this to make the C
preprocessor do 90% of the work of "translating" programs to C.  If
#define didn't work correctly, I'd have to do something kludgy like
   #define then /**/
which I'd rather not do on general principal.  On a more general ground,
I'd much prefer the first #define above to behave literally ("Replace
'then' with nothing at all.") than to have the preprocessor make some
sort of special case out of it.  If I wanted "then" to be "1", I'd
rather say so explicitly.  Let's keep C reasonably simple.  It makes
my job easier.

			John Chambers (one of several)

jc@mit-athena.UUCP (John Chambers) (02/26/85)

> C source:				Output from preprocessor:
> ===================================	=======================================
> #include <stdio.h>			...  (stuff from the include file here)
> #define	X
> main()					main()
> {					{
> 	printf("This is X: %d\n",X);		printf("This is X: %d\n",);
> }					}
> Clearly, X was not considered to be 1 (or anything), and when I attempted to
> used the test #if X == 1, the preprocessor complained of syntax error (since
> it translated the line into  #if  == 1 .

This is a good example of something I wish language implementors would learn
to get right.  X was considered to be something.   X is exactly what the
definition says:  a null string; an empty string; a string of length 0.

About 1500 years ago, there was a great advance in European mathematics when 
they learned from the Arabs about the number zero.  Previous to this, zero
was not considered to be a number, because it "didn't represent anything".
What some Arab genius realized is that, actually, zero is a number which
"represents nothing".  There is a very important distinction here.  Without
a symbol for nothing, you can't even have a balanced budget!

Character strings can be null.  To say that X is a null string is not 
to say that X doesn't represent anything; it is to say that X represents 
nothing.  These phrases are not equivalent; the first leads to confusions 
like people on the net are having, as well as to compilers that make 
funny irregular special cases out of "missing" tokens; the second leads 
to the useful understanding that a symbol may usefully appear in text 
without representing anything in the end result.  Without this ability,
we can't even have comments!

One of the real pains in using lots of software is that so many programmers
haven't caught on to this 1500-year-old idea that it is useful to have a
symbol that represents nothing.  As a result, we have all these library
routines that fail when an argument is zero; we have compilers that do
funny things when symbols are missing; etc.  How can we go about teaching
all the worlds' programmers about this very useful concept?

			John Chambers

henry@utzoo.UUCP (Henry Spencer) (02/27/85)

> This is not necessary on System V release 2 C compiler. You can omit extern
> everywhere. ld will be able to handle those constructs.

It is necessary for portability, however -- something AT&T cares less
and less about these days.  AT&T to the contrary, Vr2 is not the whole
world.  Thank God.
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry

guy@rlgvax.UUCP (Guy Harris) (03/02/85)

> > This is not necessary on System V release 2 C compiler. You can omit extern
> > everywhere. ld will be able to handle those constructs.
> 
> It is necessary for portability, however -- something AT&T cares less
> and less about these days.  AT&T to the contrary, Vr2 is not the whole
> world.  Thank God.

What you meant to say was "AT&T to the contrary, UNIX is not the whole world."
S3, 4.xBSD, and even your beloved V7 also permitted you to omit 'extern'
everywhere; all AT&T did in S5R2 (possibly S5R1; I don't know whether S5R1
had the 'extern' restriction, or whether it was in UNIX 5.0 but taken out
at the last minute when it was issued to the rest of the world) was to take
*out* the restriction that had been put into the 5.0 linker, because it, to
coin a phrase, "broke many existing programs".  Of course, if those programs
were ever intended to run on a non-UNIX system, they were already broken...

	Guy Harris
	{seismo,ihnp4,allegra}!rlgvax!guy

boris@sftri.UUCP (B.Altman) (03/03/85)

> > This is not necessary on System V release 2 C compiler. You can omit extern
> > everywhere. ld will be able to handle those constructs.
> 
> It is necessary for portability, however -- something AT&T cares less
> and less about these days.  AT&T to the contrary, Vr2 is not the whole
> world.  Thank God.
> -- 
> 				Henry Spencer @ U of Toronto Zoology
> 				{allegra,ihnp4,linus,decvax}!utzoo!henry
 I guess I should put a disclaimer.
 The opinion presented here is my own and not of ATT or anyone else.

 The section 7.2 External data definitions of "Draft proposed C standard"
 indicates that you CAN omit "extern". When the standard gets acceptance,
 I do not think argument "standard is not the whole world" will be sufficient
 reason to "play tricks" just to be able to compile on some nonconforming
 C compiler.
 To give you just a bit of history, when Bell Labs were trying to enforce
 K&R rule on externs many people were very unhappy, since it broke
 a lot of code. That is why "multiple externs" were implemented in SVR2.

				Boris Altman
				AT&T Bell Labs, Summit NJ
				{ihnp4,ucbvax}!attunix!boris

henry@utzoo.UUCP (Henry Spencer) (03/05/85)

>  The section 7.2 External data definitions of "Draft proposed C standard"
>  indicates that you CAN omit "extern".

Please read it more carefully.  In my copy of the current (11 Feb 1985)
draft, section C.7.2 describes what the *definition* of an external
variable looks like, and says there must be one.  Note, "one", not
"one or more".  To quote:

	A declaration of an identifier of an object outside of any
	function without an initializer, and without a storage-class
	specifier [e.g. "extern"] ... constitutes a *tentative*
	*definition*.  If a definition is encountered later in the
	source file, all tentative definitions are taken to be
	declarations of the same object...  If no subsequent definition
	is encountered, the first tentative definition is taken to be
	a definition with initializer equal to 0.

In other words, if the variable is initialized nowhere, then a
declaration without "extern" is the definition of the variable.  From
C.1.2.2 we learn:

	If an identifier declared with external linkage is used in an
	expression, somewhere in the entire program there must be
	exactly one *external definition* for the identifier...

"extern" is optional in external *declarations*.  But it must not
appear in the *definition*, and the tentative-definition rules boil
down to saying that, in most cases of declarations outside functions,
"extern" must in fact appear so that the declaration is not confused
with a definition.

> To give you just a bit of history, when Bell Labs were trying to enforce
> K&R rule on externs many people were very unhappy, since it broke
> a lot of code. That is why "multiple externs" were implemented in SVR2.

Unfortunately, there exist many systems which *cannot* implement the
labelled-common model of externs ("multiple externs") in any plausible
way.  Most any system with a non-Unix linker has this problem, in fact.
So the standard most assuredly specifies that conforming programs must
observe this one-definition rule.  Note that "multiple externs" are
explicitly mentioned in E.5.4.8 as a "common extension".
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry