C++ Preprocessor #Define-Ing a Keyword. Is It Standards Conforming

C++ preprocessor #define-ing a keyword. Is it standards conforming?

In C++, the closest thing to forbidding #defineing a keyword is §17.4.3.1.1/2, which only disallows it in a translation unit that includes a standard library header:

A translation unit that includes a header shall not contain any macros that define names declared or defined in that header. Nor shall such a translation unit define macros for names lexically identical to keywords.

The second sentence of that paragraph has been changed in C++0x to outright forbid #defineing a keyword (C++0x FCD §17.6.3.3.1):

A translation unit shall not #define or #undef names lexically identical to keywords.

Edit: As pointed out by Ken Bloom in comments to his answer, the rules have not changed in C++0x; the text has just been rearranged to confuse people like me. :-)

Redefine(#define) reserved c++ key word

Is it possible? Yes. Is it good style? Absolutely not.

The preprocessor is not aware of C/C++ keywords, it only knows about preprocessor tokens and just does strict text replacement.

Your example is resulting in an error because you're #undefing it. Once you undefine it, it reverts to its previous behavior.

The only valid use I know of for doing something like this is to work around a bug in an old compiler, and that compiler is no longer relevant these days.

At what stage of compilation are reserved identifiers reserved?

(The comments on the question explain that we're talking about reserved identifiers in the sense of C99 section 7.1.3, i.e., identifiers matching /^_[A-Z_]/ anywhere, /^_/ in file scope, /^str[a-z]/ with external linkage, etc. So here's my guess at at least a part of what you're asking...)

They're not reserved in the sense that (any particular phase of) the compiler is expected to diagnose their misuse. Rather, they're reserved in that if you're foolish enough to (mis)use them yourself, you don't get to complain if your program stops working or stops compiling at a later date.

We've all seen what happens when people with only a dangerous amount of knowledge look inside system headers and then write their own header guards:

#ifndef _MYHEADER_H
#define _MYHEADER_H
// ...
#endif

They're invoking undefined behaviour, but nothing diagnoses this as "error: reserved identifier used by end-user code". Instead mostly they're lucky and all is well; but occasionally they collide with an identifier of interest to the implementation, and confusing things happen.

Similarly, I often have an externally-visible function named strip() or so:

char *strip(char *s) {
// remove leading whitespace
}

By my reading of C99's 7.1.3, 7.26, and 7.26.11, this invokes undefined behaviour. However I have decided not to care about this. The identifier is not reserved in that anything bad is expected to happen today, but because the Standard reserves to itself the right to invent a new standard str-ip() routine in a future revision. And I've decided that I reckon string-ip, whatever that might be, is an unlikely name for a string operation to be added in the future -- so in the unlikely event that happens, I'll cross that bridge when I get to it. Technically I'm invoking undefined behaviour, but I don't expect to get bitten.

Finally, a counter-example to your point 4:

#include <string.h>
#define memcpy(d,s,n) (my_crazy_function((n), (s)))
void foo(char *a, char *b) {
memcpy(a, b, 5); // intends to invoke my_crazy_function
memmove(a, b, 5); // standard behaviour expected
}

This complies with your 4.1, 4.2, 4.3 (if I understand your intention on that last one). However, if memmove is additionally implemented as a macro (via 7.1.4/1) that is written in terms of memcpy, then you're going to be in trouble.

Is there a way to use a keyword as identifier in an enum?

No they cant be used.

From MSDN

Keywords are predefined reserved identifiers that have special
meanings. They cannot be used as identifiers in your program.

The rule for identifier says:

An identifier can be used to name objects, references, functions,
enumerators, types, class members, namespaces, templates, template
specializations, parameter packs, goto labels, and other entities,
with the following exceptions:

  • the identifiers that are keywords cannot be used for other purposes;
  • the identifiers with a double underscore anywhere are reserved;
  • the identifiers that begin with an underscore followed by an uppercase letter are reserved;
  • the identifiers that begin with an underscore are reserved in the global namespace.

What is the expected output when redefining true to false and vice versa?

As Jerry Coffin notes, you cannot define a macro with a name that is a keyword.

However, we could consider another, similar example, with well-defined behavior and the same result. Consider:

int TRUE = 1;
int FALSE = 0;

#define TRUE FALSE
#define FALSE TRUE

std::cout << FALSE << TRUE;

When you use FALSE, it is identified as the macro FALSE and is replaced by that macro's replacement list, which is the single token, TRUE. That replacement is then rescanned for further macros to replace.

The TRUE in the replacement is then identified as a macro and is replaced by its replacement list, which is the single token FALSE. That replacement is again rescanned.

If we continued on rescanning and replacing, we'd end up in an infinite loop, so the C (and C++) preprocessing specifications state that macro replacement never recurses within a replacement list.

Since replacement of FALSE in this final replacement list would result in recursion, macro replacement stops and we are left with FALSE, which is the name of an int with a value of 0.

Use the keyword class as a variable name in C++

try something like this:

#define class class_variable
// if class is only used in declarations, you can also do
// #define class
#include "c.h"
#undef class

it may cause problems, but maybe worth a shot

alternative (using Makefile):

python_.hpp: /usr/include/python.h
perl -pe 's/\Wclass\W//g' $< > $@
...

#include "python_.hpp"


Related Topics



Leave a reply



Submit