C макрос, строковой переменной - PullRequest
0 голосов
/ 31 января 2019

Когда я могу передать значение переменной в макрос для строкового преобразования?

Например, код, взятый из этого поста , работает с макросом с определенной константой.

#define MAX_STRING_LENGTH 20
#define STRINGIFY(x) STRINGIFY2(x)
#define STRINGIFY2(x) #x

{
  ...
  char word[MAX_STRING_LENGTH+1];     
  scanf("%" STRINGIFY(MAX_STRING_LENGTH) "s", word);
  ...
}

Однако я не могу использовать его с такой переменной, как:

{
  ...
  int val = 20;
  char word[MAX_STRING_LENGTH+1];     
  scanf("%" STRINGIFY(val) "s", word);
  ...
}

, поскольку компиляция завершается с этим предупреждением:

warning: invalid conversion specifier 'v' [-Wformat-invalid-specifier]
    scanf("%" STRINGIFY(var) "s", word);
           ~~~^~~~~~~~~~~~~
test2.c:4:22: note: expanded from macro 'STRINGIFY'
#define STRINGIFY(x) STRINGIFY2(x)
                     ^
test2.c:5:23: note: expanded from macro 'STRINGIFY2'
#define STRINGIFY2(x) #x
                      ^
<scratch space>:466:2: note: expanded from here
"var"
 ^
1 warning generated

, но выполнение кода не ожидаетлюбой ввод.

Напротив, в этом другом посте можно было передать переменную этому макросу:

#define PRINT(int) printf(#int "%d\n",int)
...
int var =8;
PRINT(var);

В чем разница между этими двумя случаями?Как я могу изменить первый так, чтобы он принимал также переменные?

Я пытался использовать %d внутри макроса, но мне это не удалось.

Ответы [ 2 ]

0 голосов
/ 31 января 2019

Препроцессор всегда работает только с токенами.

Макрос не является функцией.Вы не передаете ему переменную (по значению).Вы передаете последовательность токенов.В STRINGIFY(MAX_STRING_LENGTH) последовательность токенов равна MAX_STRING_LENGTH, а в STRINGIFY(val) это последовательность токенов val.

MAX_STRING_LENGTH сама является макросом, и из-за того, как STRINGIFY определен для работы, макрос будет расширен препроцессором, прежде чем превратить его в строковый литерал.Таким образом, 20, в свою очередь, является токеном, к которому применяется #, и выдает "20" в виде строкового литерала.

С другой стороны, val не является макросом, препроцессорне собираюсь его расширять.Он будет сохранять последовательность токенов как val.Факт val - это имя переменной, значение которой для препроцессора означает ничто , оно заботится только о токенах.Таким образом, val преобразуется в литерал "val".

Пример, который вы привели из другого поста, работает, потому что он расширился до следующего:

printf("var" "%d\n", var);

Имя переменной в #int превращаетсяв литерал, нет волшебства, которое позволяет препроцессору читать значение переменной.Факт var 8 напечатан только потому, что var передается в качестве аргумента printf!Он печатается во время выполнения спецификатором %d.

Наконец, при экспериментировании с препроцессором всегда полезно посмотреть исходный файл после выполнения prpeprocessing, но до его компиляции.Флаг gcc -E (или эквивалент для вашего компилятора) может помочь вам сделать это.

0 голосов
/ 31 января 2019

STRINGIFY(val) приведет к "val", а не к значению, которое вы хотите преобразовать в строку, поэтому вы получите окончательную строку формата "%vals" ("%" "val" "s").Вот как работает препроцессор C, он просто заменяет текст, ничего больше.

Пример PRINT:

#define PRINT(int) printf(#int "%d\n", int)

PRINT(var);                // to be resolved
printf(#var  "%d\n", var); // intermediate result
printf("var" "%d\n", var); // final result, this is what the C compiler sees

Но почему он работал с MAX_STRING_LENGTH?

#define MAX_STRING_LENGTH 20
#define STRINGIFY(x) STRINGIFY2(x)
#define STRINGIFY2(x) #x

STRINGIFY(MAX_STRING_LENGTH)  // to be resolved
STRINGIFY2(20)                // intermediate step; STRINGIFY2 known as macro, thus:
#20                           // another intermediate step
"20"                          // final result
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...