Reputation: 155
Modern C++ compilers are required by the standard to #define
the macro __cplusplus
.
This is often used in files that can be used by both C and C++ but the implementation differs slightly.
But in C (and C++ for that matter), the behaviour on using any double underscore in an identifier is undefined!
So therefore, if a C compiler sees something like
#ifdef __cplusplus
then is the behaviour undefined?
Upvotes: 1
Views: 500
Reputation: 12698
No, there's no undefined behaviour in this case. Undefined behaviour means the compiler makers are free of doing whatever they want with the affected resources. This means you are free (in this context) to define new non clashing underscored identifiers to be accepted in the two languages the compiler is able to implement. Think that the internals of the standard libraries implementations of compiler libraries can be full of such undefined behaviours as far as the compiler behaves correctly in the defined behaviour part. In the case commented, the macro __cplusplus
is defined ONLY in C++ (by the compiler itself), and it is as a preprocessor flag to indicate that you are compiling a c++ source. Putting it between the #ifndef __cplusplus
and the following #endif
statements, makes it to exclude for compilation the in between code (normally, because it would lead to a syntactic error or an unsupported feature). Normally, you will find the following construct in some/many C/C++ standard headers in your system (so they can be used in both C and C++):
#ifndef __cplusplus
extern "C" {
#endif
...
#ifndef __cplusplus
}
#endif
to avoid the extern "C" {}
construct, which is C++ specific, and would raise a compiler error in plain C.
of course, if you #define __cplusplus
before including any of these files, you'll get your C compiler shouting at you about bad syntax on including such a header file. You can try this yourself to see how it happens:
#define __cplusplus 20170301
#include <stdio.h>
int main()
{
printf("Hello, world!\n");
} /* main */
and then compilation of this gives:
$ make pru
cc -O -pipe pru.c -o pru
In file included from pru.c:2:
/usr/include/stdio.h:159:1: error: expected identifier or '('
__BEGIN_DECLS
^
/usr/include/sys/cdefs.h:59:30: note: expanded from macro '__BEGIN_DECLS'
#define __BEGIN_DECLS extern "C" {
^
In file included from pru.c:2:
/usr/include/stdio.h:235:1: error: expected identifier or '('
__BEGIN_DECLS
^
/usr/include/sys/cdefs.h:59:30: note: expanded from macro '__BEGIN_DECLS'
#define __BEGIN_DECLS extern "C" {
^
pru.c:6:2: warning: implicitly declaring library function 'printf' with type 'int (const char *, ...)' [-Wimplicit-function-declaration]
printf("Hello, world!\n");
^
pru.c:6:2: note: include the header <stdio.h> or explicitly provide a declaration for 'printf'
1 warning and 3 errors generated.
*** Error code 1
Stop.
make: stopped in /home/user
Think that you are never going to move the standard header files to another computer to compile your source code. Should you try this, then you would have undefined behaviour, but never while respecting the compiler implementation. This means, you have to accept the compiler makers to use those undefined behaviour things that result in compiler implementation details, but you cannot do that in your code (at least if you don't want to fail into your program doing nasty things)
Upvotes: 0
Reputation: 6555
The corresponding part from the standard is(emphasis mine):
7.1.3 Reserved identifiers
1 Each header declares or defines all identifiers listed in its associated subclause, and optionally declares or defines identifiers listed in its associated future library directions subclause and identifiers which are always reserved either for any use or for use as file scope identifiers.
So a little bit contrary to what Ven posted, this is an implicit requirement to not use them at all, since they are also reserved for future purposes.
This is also stated more strict under section 2 of 7.1.3:
No other identifiers are reserved. 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.
So they are strictly reserved for future implementations, which for example __cplusplus
is making use of, as the first rule that defines what is reserved states:
— All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use.
But since your example is implemented by the standard by using an identifier from that mentioned reserved spectrum it is fine.
Additionally the example you are giving is actually not declaring/defining an identifier but checking if there is a preprocessing token(macro) is defined with the name __cplusplus
what would be totally ok by means of the C standard aswell, since its checking if it exists, not declaring anything.
If you would have defined it your self, it would be not strictly respecting the C standard and cause possible undefined behavior.
Upvotes: 1
Reputation: 214310
Using such names for creating your own macros or identifiers invokes undefined behavior. C11 7.1.3 (emphasis mine):
7.1.3 Reserved identifiers
1 Each header declares or defines all identifiers listed in its associated subclause, and optionally declares or defines identifiers listed in its associated future library directions subclause and identifiers which are always reserved either for any use or for use as file scope identifiers.
— All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use.
...2 No other identifiers are reserved. 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.
However, you are of course always free to use the macros/identifiers provided by the compiler/lib, given that they are made available in a scope you are supposed to have access to.
Upvotes: 2
Reputation: 19040
But in C (and C++ for that matter), the behaviour on using any double underscore in an identifier is undefined!
You're mixing things up. It's not undefined behavior to use one, it's just that the names are reserved. The key point is you can't define some yourself, but it's fine to use them.
From ISO 9899:2011:
7.1.3 Reserved identifiers
— All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use.
Upvotes: 8