Что особенно важно для R и L в препроцессоре С++? - программирование
Подтвердить что ты не робот

Что особенно важно для R и L в препроцессоре С++?

Я выполнил следующий код через препроцессор Visual Studio 2013. Результат меня удивляет.

Содержание hello.cpp:

#define A(j) #j

A(A?)
A(B?)
A(C?)
A(D?)
A(E?)
A(F?)
A(G?)
A(H?)
A(I?)
A(J?)
A(K?)
A(L?)
A(M?)
A(N?)
A(O?)
A(P?)
A(Q?)
A(R?)
A(S?)
A(T?)
A(U?)
A(V?)
A(W?)
A(X?)
A(Y?)
A(Z?)

Команда:

cl /P hello.cpp

hello.i содержит:

#line 1 "hello.cpp"



"A?"
"B?"
"C?"
"D?"
"E?"
"F?"
"G?"
"H?"
"I?"
"J?"
"K?"
"L"
"M?"
"N?"
"O?"
"P?"
"Q?"
"R"
"S?"
"T?"
"U?"
"V?"
"W?"
"X?"
"Y?"
"Z?"

Я столкнулся с этим, пытаясь назвать A (L? p: q), что привело к "Lp: q", что не очень хорошо для меня.

Является ли это правильным, четко определенным С++? Что особенного в L и R на С++? Если файл имеет расширение .c, то L и R обрабатываются идентично остальной части алфавита. Связано ли это с С++ 11? Это должна быть новая функция, поскольку более старые версии MSVS не проталкивают L и R особым образом.

И что я могу сделать, чтобы остановить MSVS 2013 от обработки L и R этим специальным способом?

4b9b3361

Ответ 1

Обновить

Похоже, что отчет об ошибке был отмечен как дубликат этого, в котором есть обновление, в котором говорится:

Исправление для этой проблемы было проверено в источниках компилятора. Исправление должно появиться в следующей крупной версии Visual С++.

Оригинал

Как пояснил Remyabel, это сообщенная ошибка. Ни gcc, ни clang не дают эти результаты, а оператор строки # в соответствии с документами Visual Studios, это следующие замены (акцент мой вперед):

Пробел, предшествующий первому токену фактического аргумента и следующему последнему токену фактического аргумента, игнорируется. Любое пустое пространство между токенами в фактическом аргументе сводится к одному пробелу в результирующем строковом литерале. Таким образом, если комментарий имеет место между двумя токенами в фактическом аргументе, он сводится к одному пробелу. Получившийся строковый литерал автоматически объединяется с любыми смежными строковыми литералами, из которых он разделяется только пробелом.

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

что соответствует С++ draft standard 16.3.2 Оператор #, который говорит:

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

Единственное, что связывает R и L относительно С++ 11, состоит в том, что они имеют особое значение с строковыми литералами но я не вижу, как это должно повлиять на этот случай.

Похоже, что L\ и R\ также выдают ту же проблему.

Они документируют несоответствующую проблему, и он говорит:

Visual С++ не ведет себя корректно, когда оператор # (stringize) используется со строками, включающими escape-последовательности. В этой ситуации компилятор будет генерировать ошибку компилятора C2017.

который не охватывает этот случай.

Ответ 2

Это похоже на ошибку в препроцессоре MSVC. Хорошая новость заключается в том, что в зависимости от того, насколько вы придирчивы к вашему результату, вы можете обойти проблему, разместив пространство после R или L.

A(L ?p:q), // "L ?p:q"