0
votes

I wrote a simple C program to test the availability of _Generic keyword.

int main() {
    int _Generic;
}

I ran the program with gcc-5.3.1 and clang-3.8.0 compilers on Ubuntu.

Obviously this program generated an error when compiled in the latest c11 standard.

But, when compiled with -std=c90 and -std=c99 flags, it generated an error as well. Whereas, the _Generic keyword was only introduced in c11 standard.

Is it that the -std= flags behave differently? And is there a way to test the pure c90 and c99 standards?

EDIT:

I did run the same program with other identifiers which are not keywords as per c11 standard. Like:

int _Hello;
int _Gener;

And they compiled successfully without any errors or warnings. This is probably because of 7.1.3, which says

If the program declares or defines an identifier in a context in which it is reserved (other than as allowed by 7.1.4), or defines a reserved identifier as a macro name, the behavior is undefined

as said by @Art and @Lundin.

1
isn't it like anything starting with underscore is "reserved"? or am I being too aggressive? edit: It's __ or _<uppercase>, to be precise. - Sourav Ghosh
ANSI C: "All other identifiers that begin with an underscore and either an upper-case letter or another underscore are reserved. If the program defines an external identifier with the same name as a reserved external identifier, even in a semantically equivalent form, the behavior is undefined.". So the compiler is technically correct. - Art
@Art: Note that "the behavior of X is undefined" isn't intended to mean "programs that seek merely to be conforming, rather than strictly conforming, are forbidden from doing x", but rather that the Standard is agnostic as to whether implementations should process X usefully. I think the intention here is to give implementations a family of identifiers to which they may attach any behavior they would regard as useful--not to suggest that implementations do anything wacky with any identifiers to which they haven't attached useful meanings. Among other things... - supercat
...implementations which by convention define reserved-name macros for each new identifier (e.g. treating __WOOZLE as a predefined macro for the new intrinsic ___WOOZLE) could add features and allow code to use them while maintaining compatibility with older code via e.g. #ifndef __UNSPEC_CHOICE(x,y) #define __UNSPEC_CHOICE(x,y) x #endif. If a new compiler will interpret that as an intrinsic that expands to x or y, whichever is more efficient, code which is written to exploit that, but starts with the above #ifdef, could work on old or new compilers. - supercat

1 Answers

7
votes

Because you are not allowed to use identifiers that start with an underscore followed by an upper-case letter. 7.1.3:

All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use.

This rule has been there since C90 and is nothing new.


A more reliable way to test for standard version would be to use the standard macros defined for that very purpose:

#ifndef __STDC__
  #error Not a standard C compiler.
#endif

#ifdef __STD_VERSION__
  #if (__STDC_VERSION__ == 199409L)
    /* C95 */
  #elif (__STDC_VERSION__ == 199901L)
    /* C99 */
  #elif (__STDC_VERSION__ == 201112L)
    /* C11 */
  #else
    /* Cxx, unknown future standard */
  #endif
#else /* __STDC__ defined but not __STD_VERSION__ */
  /* C90 */
#endif