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