Условное включение: числовое значение символьных констант: внутри #if/#elif и без #if/#elif: почему сопоставление определяется реализацией?
Случай A: C11, 6.6 Постоянные выражения, семантика, 5:
Если плавающее выражение оценивается в среде перевода, арифметический диапазон и точность должны быть как минимум такими же большими, как если бы выражение оценивалось в среде выполнения.116)
который требует, чтобы следующая программа возвращала 0:
#include <float.h>
#define EXPR DBL_MIN * DBL_MAX
double d1 = EXPR;
double d2;
#pragma STDC FENV_ACCESS ON
int main(void)
{
d2 = EXPR;
return d1 == d2 ? 0 : 1;
}
Случай B: C11, 6.10.1 Условное включение, семантика, 4:
Соответствие числового значения этих символьных констант значению, полученному, когда идентичная символьная константа встречается в выражении (кроме директив #if или #elif), определяется реализацией.168)
который не требует, чтобы следующая программа возвращала 0:
#define EXPR 'z' - 'a' == 25
int main(void)
{
_Bool b1 = 0;
_Bool b2;
#if EXPR
b1 = 1;
#endif
b2 = EXPR;
return b1 == b2 ? 0 : 1;
}
Вопрос: каково обоснование создания поведения, определяемого реализацией, "Case B"?
1 ответ
Стандарт C11 (я буду цитировать этот проект документа ) определяет два набора символов:
5.2.1 Наборы символов
1 Должны быть определены два набора символов и связанные с ними последовательности сопоставления: набор, в котором записываются исходные файлы ( исходный набор символов), и набор, интерпретируемый в среде выполнения ( набор символов выполнения). Каждый набор далее делится на базовый набор символов, содержание которого дается в этом подпункте, и набор из нуля или более членов, специфичных для локали (которые не являются элементами основного набора символов), называемых расширенными символами. Комбинированный набор также называется расширенным набором символов . Значения членов набора символов выполнения определяются реализацией.
Кроме того, нет требования, чтобы эквивалентные символы в этих наборах были представлены одними и теми же значениями, и нет требования, чтобы латинские буквы хранились в определенной последовательности. Так, в приведенном примере значение
Теперь порядок фаз трансляции указывает, что вызовы макросов и оценки (и другие директивы предварительной обработки) выполняются с использованием исходного набора символов, но выражения, которые встречаются в исполняемом коде, оцениваются после преобразования в набор символов выполнения:
5.1.1.2 Фазы перевода
…
4. Директивы предварительной обработки выполняются, вызовы макросов расширяются, и_Pragma
выполняются унарные операторные выражения. Если последовательность символов, соответствующая синтаксису универсального имени символа, создается конкатенацией маркеров (6.10.3.3), поведение не определено. А#include
директива предварительной обработки вызывает рекурсивную обработку именованного заголовка или исходного файла с фазы 1 по фазу 4. Затем все директивы предварительной обработки удаляются.
5. Каждый элемент исходного набора символов и управляющая последовательность в символьных константах и строковых литералах преобразуются в соответствующий член набора символов выполнения; если соответствующий член отсутствует, он преобразуется в определяемый реализацией член, отличный от нулевого (широкого) символа.
…
Таким образом, поскольку взаимосвязь между этими наборами символов определяется реализацией, и поскольку два экземпляра константных выражений на основе символов определены для использования разных наборов, тот факт, что они могут иметь разные оценки , также должен определяться реализацией.