В следующем примере:

#define PRNT(x, y) printf("X is %s and Y is %s\n", #x, #y)
int main(void)
{
    PRNT("HELLO", 4);
}

Это дает:

X - это "ПРИВЕТ", а Y - 4.

Не мог бы кто-нибудь рассказать мне, как препроцессор выполняет замену в приведенном выше? Например, почему бы ему не оценить:

  1. Начало: printf("X is %s and Y is %s\n", #x, #y)
  2. Добавьте x = "Hello", y = 4: printf("X is %s and Y is %s\n", "Hello", 4)
  3. Printf должен вернуть: X is Hello and Y is 4\n <- HELLO not "HELLO"

Итак, как / почему он добавляет дополнительный " вокруг HELLO; то есть, почему он печатает ..."HELLO"... вместо просто ...HELLO...? Преобразует ли препроцессор кавычки в строке в \", чтобы они становились \"HELLO\" и "4" при передаче этих двух аргументов в функцию printf?

c
1
David542 1 Мар 2021 в 23:57

7 ответов

Лучший ответ

Преобразует ли препроцессор кавычки в строке в \" так, чтобы они становились \"HELLO\" и "4" при передаче этих двух аргументов в функция printf?

Да.

Если вы согласны принять документацию Microsoft, тогда см. здесь:

Кроме того, если символ, содержащийся в аргументе, обычно требует escape-последовательности при использовании в строковом литерале, например, кавычки (") или обратной косой черты (\)", необходимая обратная обратная косая черта автоматически вставляется перед символом.

Или, если вы предпочитаете более официальную версию, вот что это Стандарт C11 (черновик) говорит:

6.10.3.2 Оператор #


2 Семантика

… В противном случае исходное написание каждого токена предварительной обработки в аргументе сохраняется в символьном строковом литерале, за исключением специальной обработки для создания написания строковых литералов и символьных констант: перед каждым символом "и \" символа вставляется символ \ константный или строковый литерал (включая ограничивающие "символы),

3
Adrian Mole 1 Мар 2021 в 21:21

Это было бы верно для x, y, но не для #x, #y, в котором используется модификатор "стринги".

Если вы преобразовываете строку в строку, вы просто получаете строку, но она будет содержать окружающие кавычки. Если вы построите число, вы получите строку.

Как правило, для данного x вы получите "x", поэтому для "x" вы получите "\"x\"".

3
tadman 1 Мар 2021 в 21:03

#X дает строковый литерал, содержимое которого равно X. Таким образом, # с аргументом "FOO" дает строковый литерал, пять символов которого: ", F, {{X5 }}, O, ". (И, конечно, нулевой терминатор)

Предварительная обработка происходит после токенизации кода и обработки управляющих последовательностей, а результатом предварительной обработки является поток токенов (а не какой-то исходный файл, требующий повторной токенизации и повторной обработки escape-последовательностей).

2
M.M 1 Мар 2021 в 21:04

"HELLO" - это токен, который вы передаете в свой макрос. Оператор # превращает это в строку, так что ваша строка будет "\" HELLO \ "", так же как когда вы передаете число 4, оно становится "4". Поэтому, когда препроцессор запускается, я ожидаю, что ваш код будет выглядеть так:

int main(void)
{
    printf("X is %s and Y is %s\n", "\"HELLO\"", "4");
}
2
Christian Gibbons 1 Мар 2021 в 21:04

Это происходит из-за символа «#» перед переменными внутри макроса. Он называется оператором "стягивания", и он принимает входную переменную и, ну, в общем, преобразовывает ее в строку. Это означает размещение его в кавычках, а также экранирование уже имеющихся в переменной. Это означает, что при раскрытии "Hello" становится "\"Hello\"", а 4 становится "4".

2
Matthias Raba 1 Мар 2021 в 21:11

При преобразовании в строку (что происходит, когда вы делаете что-то вроде #x в макросе) элемент превращается в строку. В случае 4 вы получите "4", в случае "HELLO" вы получите "\"HELLO\"", потому что обе из них являются точной строкой, которая вам понадобится для воспроизведения элемент при его печати, например.

Многие компиляторы имеют возможность останавливаться после предварительной обработки, чтобы вы могли изучить ее эффекты, например, с помощью флага -E для gcc:

pax:~> gcc --std=c17 -E prog.c
# 1 "prog.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "prog.c"

int main(void)
{
    printf("X is %s and Y is %s\n", "\"HELLO\"", "4");
}
1
paxdiablo 1 Мар 2021 в 21:23

#x преобразует x в строку.

Т.е.

x = "Hello"

Затем

#x = "\"Hello\""
0
Ed Heal 1 Мар 2021 в 21:04