5

Согласно стандарту C11, аргумент функционально-подобного макроса может содержать пробелы в начале или в конце последовательности токенов предварительной обработки. Для нормальной замены такие пространства не имеют никакого эффекта. Для стенообразования пробелы следует игнорировать, как указано в 6.10.3.2.2C аргументы макропроцессора препроцессора с пространством в конце для конкатенации?

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

(который я считаю, также доказательства того, что аргументы могут иметь пробелы вокруг него.) И вопрос, аргументы, которые будут сцепленных от ## оператора, что следует делать компилятор о своих пространствах?

Я пробовал его с VC++, который, кажется, просто игнорирует пробелы.

Я думаю, что компилятор должен выполнить конкатенацию с пробелом. Это может привести к недопустимому токену, например, «ABC», сформированному идентификатором ABC, и аргументу с пробелом в качестве первого токена. Согласно стандарту, если недействительный токен формируется таким образом, поведение не определено.

Итак, что сделал VC++, как упоминалось ранее, является ли это результатом просто игнорирования пробела или результата неопределенного поведения?

ответ

4

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

Нет, на самом деле это только укрепляет положение эталона, что каждый макрос аргумент является последовательность предварительной обработки лексем (C2011, 6.10.3/11). Пробелы в исходном файле разделяют токены предварительной обработки; пробелы пробелов не являются самими препроцессорными жетонами.

Раздел стандартного номера, который вы цитируете, потенциально запутан, потому что он смешивает уровни - последовательность символов исходного файла, к которому относится пробел, и последовательность токенов предварительной обработки, возникающая из-за цельной токенизации исходной последовательности. Действительно, стробирование чувствительно к тому, что соседние маркеры разделены пробелом в исходной последовательности символов, но детали любого такого пробела вообще не имеют значения - при строкообразовании смежные маркеры, разделенные пробелами, разделяются одним пространством символ в результирующей строке.

Это не означает, что токен предварительной обработки может начинаться или заканчиваться пробелом. Это невозможно; подробные сведения см. в разделе 6.4 стандарта.То, как данная реализация удовлетворяет спецификациям для строкования, обязательно является специфичной для реализации, но один из способов реализации этой реализации мог бы включать в себя сохранение булевых флагов для каждого токена предварительной обработки, описывающего, предшествует ли этот токен и/или следует в исходной последовательности по пробелам. Такие данные не имеют ничего общего с интерпретацией того, что стандарт указывает на результат, однако, ни для оператора строковой обработки, ни для оператора вставки меток.

для аргументов, которые будут объединены оператором ##, что должен делать компилятор относительно его пространств?

К тому времени ## оператора (или оператора #) входит в игру, компилятор уже сделал все, что когда-либо будет (непосредственно) делать с пробельных символов появляется в исходном файле, рассматривая их в токенизации из источник в токены предварительной обработки. Макро-аргументы - это последовательности токенов предварительной обработки, и только в той степени, в которой эти токены могут быть строковыми или символьными литералами или именами заголовков, могут содержать пробелы. Кроме того, стандарт определяет:

Если в списке замещения функции, как макро, параметр непосредственно предшествуют или следует ## предварительной обработки маркера, параметр заменяется соответствующим аргумент предварительной обработки маркера последовательность [...]

(C2011, 6.10.3.3/2; курсив добавлен)

Еще раз, пробельные пробеги не Preprocessing маркеры. Расширение макроса и операторы # и ## имеют дело с уровнями последовательностей токенов предварительной обработки и работают с ними. Пробелы представлены на этом уровне только внутри маркеров. Пробел из исходного файла, который не является внутренним для токена предварительной обработки, представлен только косвенно и неопределенно в последовательности токенов предварительной обработки.

+0

Я вижу. Большое вам спасибо за ваш ответ. Но мне интересно, если компилятор не включает пробел в последовательности токенов предварительной обработки аргумента, как он будет выполнять строчение? Я имею в виду, как он должен знать, куда помещать пробел между соседними токенами предварительной обработки, а где нет. Думаю, это не только записывает последовательность токенов, но и информацию о белых пробелах? Что говорит об этом стандарт? –

+0

@WuZhenwei, вы правы, что стробирование не вставляет пробел между токенами предварительной обработки, где в исходной последовательности символов нет. Поскольку препроцессору не важно, сколько пробелов есть или какие конкретные символы пробелов находятся в таких местах, он может отслеживать по принципу токена-маркера, должны ли перед знаками предшествовать и/или сопровождаться пробелами. Это деталь реализации. Я уточню свой ответ, чтобы уточнить. –

3

6.10.3.3/3

перед списком замещающей пересматриваются для более макроимен заменить каждый экземпляр: ## предварительной обработки маркера в списке замены (не из аргумента) удаляется а предшествующая предварительная обработка токена объединяется с следующим токеном предварительной обработки.

So ## объединяет два токена предварительной обработки. Не имеет значения, будут ли аргументы, которые они взяты, содержать пробелы.

+0

Вы имеете в виду, что это некое неопределенное поведение, которое VC++ игнорирует пространство? (См. Последнее предложение моего вопроса.) –

+1

@WuZhenwei no Я не имею в виду ничего подобного. Ваше последнее предложение основано на неверной предпосылке, а именно, что препроцессор должен конкатенировать пробелы. В этом стандарте ничего нет. –

+0

Спасибо. Я думал, что пробел также может быть токеном предварительной обработки. –

Смежные вопросы