Вопрос

I've been looking through code golf and got an idea to try this code:

#define D #define after adding this line, everything worked fine, however I expanded it into this:

#define D #define
D VALUE

And here I got 5 compilation error. If I change D into #define everything is fine, can someone explain, why this code is illegal?

NOTE: I used VS2008 compiler.

EDIT: After some answers I see that I needed to give compilations error list:

  1. error C2121: '#' : invalid character : possibly the result of a macro expansion
  2. error C2146: syntax error : missing ';' before identifier 'VALUE'
  3. error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
  4. error C2144: syntax error : 'void' should be preceded by ';'
  5. error C4430: missing type specifier - int assumed. Note: C++ does not support default-int

First error shows that D is not just define but also includes #.

Это было полезно?

Решение 2

This code is illegal because language specification says it is illegal. According to C and C++ preprocessor specification, whatever code you build using preprocessor will never be interpreted as another preprocessor directive. In short, you cannot build preprocessor directives using preprocessor. Period.

(Also, you cannot build comments using preprocessor.)

Другие советы

C 2011 (N1570) 6.10.3.4 3: “The resulting completely macro-replaced preprocessing token sequence is not processed as a preprocessing directive even if it resembles one,…”

C++ 2010 (N3092) 16.3.4 [cpp.rescan] 3 has exactly the same text.

It does look like your preprocessor is making the substitution you want, but you likely wouldn't get the behaviour you want - the preprocessor is normally just a single pass operation. Example (with clang, but you should be able to reproduce by using the appropriate VS2008 flags):

$ cat example.c 
#define D #define
D VALUE
$ cc -P -E example.c 

 #define VALUE

That #define VALUE is going straight through to the compiler, which won't know what to do with it - it's a preprocessor directive, after all. Clang's error, for reference, is similar to yours:

$ cc -c example.c 
example.c:2:1: error: expected identifier or '('
D VALUE
^
example.c:1:11: note: expanded from macro 'D'
#define D #define
          ^
1 error generated.

That won't work because preprocessing is performed in a single pass. For example, consider the next code :

#define MYDEFINEWEIRD #define

MYDEFINEWEIRD N 6

int main() {

  return 0;
}

After preprocessing, your code will looks like :

 #define N 6
int main() {

  return 0;
}

and "#define" is not a valid syntax on C or C++. Also, since the resulting preprocessor directive is not going to be processed, it won't resolve subsequent references to the "N" macro in your code.

Just for fun, you can call the preprocesor twice from the command line using g++/gcc. Consider the next code (define.cpp) :

#include <iostream>

#define MYDEFINEWEIRD #define
MYDEFINEWEIRD N 6

using namespace std;

int main() {
  cout << N << endl;
  return 0;
}

Then you can do:

$ g++ -E define.cpp | g++ -o define -x c++ - && ./define

and will output:

6

Lines of code in the pre-processors eyes are either pre-processor statements (And thus don't have any replacements done on them) or normal text statements (And have replacements done). You can't have one be both, so once you have 'D' be replaced it's only going to look to see if there are any more macros to replace. Since there are none, it just leaves '#define' in the C++ code as it is and then the C++ compiler will error when it sees it (Since '#define' isn't valid C++ code).

So show my point more, this is invalid code for the pre-processor:

#define D define
#D value

Because the pre-processor doesn't do any macro replacement on pre-processor statements, and "#D" isn't a recognized pre-processor command. And this:

#define D #define
D value

Results in this C++ code:

#define value

Which is invalid because the pre-processor is already done being run.

Looking at the grammar in 16 [cpp] paragraph 1, a replacement-list consists of pp-tokens which may include the production # no-directive which is described in paragraph 2 of the same paragraph as

A non-directive shall not begin with any of the directive names appearing in the list.

That is, something of the form

#define NAME # define

happens to be illegal! Also note that the # in this context does not turn the next word into a string: the quoting following a # only happens shen the # is immediately followed by a macro parameter name in a function-style macro.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top