Возьмем следующий пример:
#define FOO(x) bar x ## baz
FOO( )
Каков ожидаемый вывод приведенного выше кода в соответствии со стандартами ANSI C и C99 после фазы предварительной обработки?
Я запустилвыше через gcc -E
и clang -E
, и оба производят выход, эквивалентный следующему:
bar baz
Кроме того, если вышеупомянутый предварительно обработанный вывод считается соответствующим стандартам, то что по этому поводу?
#define FOO(x) x ## baz
FOO( )
С вышеуказанной модификацией GCC и clang по-прежнему производят вывод, эквивалентный следующему, без вывода каких-либо предупреждений или ошибок.(даже с флагами -Wall -Werror
):
baz
Я подозреваю, что вышеприведенный вывод не соответствует стандартам, потому что стандарт ANSI C 9899: 1990 гласит:
6.8.3.3 Оператор ##
A ## маркер предварительной обработки не должен появляться в начале или в конце списка замены ни для одной из форм определения макроса.
Если в списке замены естьЗа параметром непосредственно предшествует или следует ## токен предварительной обработки, параметр заменяется последовательностью токена предварительной обработки соответствующего аргумента.
Хорошо, так что технически оператор ## НЕ находится в начале списка замены в обоих приведенных выше двух примерах, но x
расширяется до ... одного пробела?ничего такого?... так что оператор ## (по крайней мере, насколько я понимаю) объединяет пробел pp-токен (или ничего) в baz
.
Кроме того, стандарт гласит:
Как для объектно-подобных, так и для функционально-подобных вызовов макросов, перед пересмотром списка замен для замены большего количества имен макросов, каждый экземпляр ## токен предварительной обработки в списке замены (не из аргумента) удаляется, а предыдущий токен предварительной обработки объединяется со следующим токеном предварительной обработки.
Итак, учитывая первый приведенный выше пример, почему не следуетскажем, это правильный вывод?
barbaz
ОБНОВЛЕНИЕ
В качестве идентификатора мне удалось заставить GCC выдать ошибку для первого примера, который я привел выше при предварительной обработке кода следующим образом:
gcc -ansi -pedantic -Wall -Werror -E ex1.c -o -
Вывод (с ошибкой):
foo.c:2:6: error: invoking macro FOO argument 1: empty macro arguments are undefined in ISO C90 [-Werror=pedantic]
FOO( )
^
# 1 "foo.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "foo.c"
bar baz
cc1: all warnings being treated as errors
Ошибка, однако, не связана с поведением оператора ## , о чем и был этот вопрос.Тем не менее, это по-прежнему интересно.
Также интересно отметить, что clang не выдает ошибку при предварительной обработке файла с использованием тех же флагов.