Макро функция для печати с UB - PullRequest
0 голосов
/ 10 января 2019

Я учусь использовать макро-функции и теперь столкнулся с некоторым (скорее всего, неопределенным) поведением. Вот пример:

#include <stdio.h>

#define FOO(a, b) { \
    printf("%s%s\n", #a #b); \
} \

int main(int argc, char * argv[]){
    { printf("%s%s\n", 1 2); } //compile error
    FOO(1, 2);                 //prints 12 with some garbage
}

Demo1

Demo2

Скорее всего, я испытываю UB, но копание в N1570 не дало четкого объяснения этому. Ближайшая вещь, которую я нашел, была 5.1.1.2(p4):

Выполняются директивы предварительной обработки, расширяются вызовы макросов, и выражения унарного оператора _Pragma выполняются. Если последовательность символов, соответствующая синтаксису универсального имени символа, равна , полученный путём конкатенации токенов (6.10.3.3), поведение не определено.

Вероятно, токены "1" "2" были объединены, давая UB, но я не уверен.

Ответы [ 2 ]

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

FOO расширяется до printf("%s%s\n", "1" "2"). Строковые литералы объединяются во время предварительной обработки, получая printf("%s%s\n", "12").

Это неправильный вызов printf и UB. Соответствующая часть в стандарте такова:

7.21.6.1 Функция fprintf
...
2 ... Если для формата недостаточно аргументов, поведение не определено.

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

Вероятно, токены "1", "2" были объединены, что дало UB, но я не уверен.

Вы правы.

«1» и «2» стали «12» и перешли к первому %s в printf(). Затем второй %s не имеет ничего для обработки, таким образом, значения мусора.

Предупреждения компилятора тоже согласны (конечно):

prog.cc:4:12: warning: format '%s' expects a matching 'char*' argument [-Wformat=]
    4 |     printf("%s%s\n", #a #b); \
      |            ^~~~~~~~
prog.cc:9:5: note: in expansion of macro 'FOO'
    9 |     FOO(1, 2);                 //prints 12 with some garbage
      |     ^~~
prog.cc:4:16: note: format string is defined here
    4 |     printf("%s%s\n", #a #b); \
      |               ~^
      |                |
      |                char*

В вашем макросе измените это:

printf("%s%s\n", #a #b);

к этому:

printf("%s%s\n", #a, #b);

где запятая поможет, как прокомментировал @Blaze. Live Demo

Примечание: для жестко закодированного printf() вызова на работу вы хотели бы сделать 1 и 2 строки; использование запятой будет недостаточно. Пример: printf("%s%s\n", "1", "2");.

...