0

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.

Aseem Sharan
  • 57
  • 1
  • 5
  • 2
    isn't it like anything starting with underscore is "reserved"? or am I being too aggressive? edit: It's `__` or `_`, to be precise. – Sourav Ghosh Jun 16 '17 at 13:09
  • 3
    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 Jun 16 '17 at 13:11
  • @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 Jul 26 '20 at 17:44
  • ...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 Jul 26 '20 at 17:47

1 Answers1

7

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
Lundin
  • 195,001
  • 40
  • 254
  • 396
  • Thanks for the answer and the reference. But, I ran the same program with other identifiers like _Hello, _Gene etc. and it compiled without any problem. Probably it is the case that behaviour is undefined as written in 7.1.3 and which was pointed out by @Art. – Aseem Sharan Jun 16 '17 at 13:53
  • 2
    @AseemSharan, exactly it is undefined, meaning what it says, not defined. So the compiler may do what pleases with your code. In view of the C11, they do already something with `_Generic` and not with the other identifiers that you tried. – Jens Gustedt Jun 16 '17 at 18:42