条件包含:字符常量的数值:在#if/#elif 内与不在#if/#elif 内:为什么匹配是实现定义的?

Conditional inclusion: numeric value for the character constants: within #if/#elif vs. without #if/#elif: why matching is implementation-defined?

案例 A:C11,6.6 常量表达式,语义,5:

If a floating expression is evaluated in the translation environment, the arithmetic range and precision shall be at least as great as if the expression were being evaluated in the execution environment.116)

需要以下程序才能return0:

#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:

Whether the numeric value for these character constants matches the value obtained when an identical character constant occurs in an expression (other than within a #if or #elif directive) is implementation-defined.168)

不需要以下程序到return0:

#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;
}

问题:使“案例 B”实现定义行为的基本原理是什么?

C11 标准(我将引用 this draft document)定义了两个字符集:

5.2.1 Character sets

1     Two sets of characters and their associated collating sequences shall be defined: the set in which source files are written (the source character set), and the set interpreted in the execution environment (the execution character set). Each set is further divided into a basic character set, whose contents are given by this subclause, and a set of zero or more locale-specific members (which are not members of the basic character set) called extended characters. The combined set is also called the extended character set. The values of the members of the execution character set are implementation-defined.

此外,不要求这些集合中的等效字符由相同的 表示,也不要求拉丁字母按顺序存储。因此,在给出的示例中,'z' - 'a' 的值在这两个集合中不必相同。

现在,翻译阶段的顺序指定宏调用和求值(以及其他 pre-processing 指令)是使用 源字符集 执行的,但是出现在可执行代码在转换为 执行字符集:

后被评估

5.1.1.2 Translation phases


4.     Preprocessing directives are executed, macro invocations are expanded, and _Pragma unary operator expressions are executed. If a character sequence that matches the syntax of a universal character name is produced by token concatenation (6.10.3.3), the behavior is undefined. A #include preprocessing directive causes the named header or source file to be processed from phase 1 through phase 4, recursively. All preprocessing directives are then deleted.
5.     Each source character set member and escape sequence in character constants and string literals is converted to the corresponding member of the execution character set; if there is no corresponding member, it is converted to an implementation-defined member other than the null (wide) character.

因此,因为这些字符集之间的关系是 implementation-defined,并且因为 character-based 常量表达式的两次出现是 定义的 使用不同集,他们可能有不同的评估的事实 也必须是 implementation-defined.