Подтвердить что ты не робот

Можно ли определить другую директиву препроцессора?

Я просматривал код для гольфа и получил идею попробовать этот код:

#define D #define после добавления этой строки все работало нормально, однако я расширил ее следующим образом:

#define D #define
D VALUE

И здесь я получил 5 ошибок компиляции. Если я изменю D на #define, все будет в порядке, может кто-нибудь объяснить, почему этот код является незаконным?

ПРИМЕЧАНИЕ: Я использовал компилятор VS2008.

EDIT: После некоторых ответов я вижу, что мне нужно предоставить список ошибок компиляций:

  • ошибка C2121: '#': недопустимый символ: возможно, результат расширения макроса
  • ошибка C2146: синтаксическая ошибка: отсутствует ';' перед идентификатором "VALUE"
  • ошибка C4430: отсутствует спецификатор типа - int. Примечание: С++ не поддерживает default-int
  • ошибка C2144: синтаксическая ошибка: "void" должен предшествовать ';'
  • ошибка C4430: отсутствует спецификатор типа - int. Примечание: С++ не поддерживает default-int

Первая ошибка показывает, что D не просто define, но также включает #.

4b9b3361

Ответ 1

Этот код является незаконным, поскольку в спецификации языка указано, что оно является незаконным. Согласно спецификации препроцессора C и С++, любой код, который вы создаете с использованием препроцессора, никогда не будет интерпретироваться как другая директива препроцессора. Короче говоря, вы не можете создавать директивы препроцессора с использованием препроцессора. Период.

(Кроме того, вы не можете создавать комментарии с помощью препроцессора.)

Ответ 2

C 2011 (N1570) 6.10.3.4 3: "Полученная полностью макрозаменяемая последовательность токенов предварительной обработки не обрабатывается как директива предварительной обработки, даже если она похожа на одну,..."

С++ 2010 (N3092) 16.3.4 [cpp.rescan] 3 имеет точно такой же текст.

Ответ 3

Это похоже на то, что ваш препроцессор делает нужную вам замену, но вы, скорее всего, не получите желаемого поведения - препроцессор обычно является просто операцией с одним проходом. Пример (с clang, но вы должны иметь возможность воспроизвести, используя соответствующие флаги VS2008):

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

 #define VALUE

То, что #define VALUE идет прямо к компилятору, который не знает, что с ним делать - это, в конце концов, препроцессорная директива. Ошибка Clang для справки аналогична вашей:

$ 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.

Ответ 4

Это не сработает, потому что предварительная обработка выполняется за один проход. Например, рассмотрим следующий код:

#define MYDEFINEWEIRD #define

MYDEFINEWEIRD N 6

int main() {

  return 0;
}

После предварительной обработки ваш код будет выглядеть так:

 #define N 6
int main() {

  return 0;
}

и "#define" не является допустимым синтаксисом на C или С++. Кроме того, поскольку результирующая директива препроцессора не будет обрабатываться, она не будет разрешать последующие ссылки на макрос "N" в вашем коде.

Просто для удовольствия вы можете дважды вызвать препроцессор из командной строки с помощью g++/gcc. Рассмотрим следующий код (define.cpp):

#include <iostream>

#define MYDEFINEWEIRD #define
MYDEFINEWEIRD N 6

using namespace std;

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

Затем вы можете сделать:

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

и выведет:

6

Ответ 5

Линии кода в глазах препроцессоров - это либо предпроцессорные операторы (и, следовательно, на них не выполняются никакие замены), либо обычные текстовые инструкции (и выполняются замены). У вас не может быть и того, и другого, поэтому, как только вы замените "D", вы увидите только, есть ли какие-либо макросы для замены. Поскольку их нет, он просто оставляет "#define" в коде С++, как есть, и тогда компилятор С++ будет ошибочен, когда увидит его (так как "#define" не является допустимым кодом С++).

Итак, покажите мою точку больше, это неверный код для предварительного процессора:

#define D define
#D value

Поскольку предварительный процессор не выполняет макрообмена в предпроцессорных операциях, а "#D" не является распознанной командой предварительного процессора. И это:

#define D #define
D value

Результаты этого кода на С++:

#define value

Это недопустимо, поскольку предварительный процессор уже выполняется.

Ответ 6

Глядя на грамматику в параграфе 16 [cpp], список замещений состоит из pp-токенов, которые могут включать в себя производственную №-директиву, которая описана в параграфе 2 того же абзаца, что и

Не директива не должна начинаться с каких-либо имен директив, входящих в список.

То есть что-то вроде формы

#define NAME # define

оказывается незаконным! Также обратите внимание, что # в этом контексте не превращает следующее слово в строку: цитирование, следующее за #, происходит только тогда, когда в строке # сразу следует имя макроопределения в макрос функционального стиля.