C最低标准要求
摘自C标准ISO/IEC 9899:201x: 一致性实施的最低要求是:C最低标准要求,c,language-lawyer,C,Language Lawyer,摘自C标准ISO/IEC 9899:201x: 一致性实施的最低要求是: 对易失性对象的访问严格按照 抽象机器的规则 在程序终止时,所有数据 写入文件的结果应与执行 该程序根据抽象语义本来会产生 交互设备的输入和输出动态应发生 如7.21.3所述。这些要求的目的是 无缓冲或行缓冲输出尽快出现,以便 确保提示消息实际出现在程序之前 等待输入 这是程序的可观察行为 这一段的意思相当戏剧性(至少对我来说),在我看来,这一段说: (1) 产生与完全符合标准的抽象机器相同的可观察行为的编译器是符合标准
- 对易失性对象的访问严格按照 抽象机器的规则李>
- 在程序终止时,所有数据 写入文件的结果应与执行 该程序根据抽象语义本来会产生
- 交互设备的输入和输出动态应发生 如7.21.3所述。这些要求的目的是 无缓冲或行缓冲输出尽快出现,以便 确保提示消息实际出现在程序之前 等待输入李>
a&b
)
(2) 没有挥发物、不写入文件和没有输入输出交互的程序实际上什么都不做,没有可观察的行为,并且可以完全优化,例如,主中的xor eax,eax
比ret
(x86-64 clang7.0.0)的两条指令
我是对的,还是说得太离谱了
是的,一个C实现(不只是一个编译器——包括标准库、链接和运行时支持,和/或用于实现C的任何其他工具),它产生与一致性抽象机器一致的可观察行为1。本标准中的所有其他要求和段落不仅仅是额外的。它们定义了抽象机器的行为,因此它们有助于描述可观察的行为必须是什么
是的,一个没有可观察行为的程序可以优化为一个只返回的程序。请注意,xor eax,eax
在技术上是不需要的。然而,这可能只是标准中的一个无意缺陷,而不是目的
笔记
1规范要求的不仅仅是程序的行为。例如,实现还必须记录各种实现定义的行为。因此,这个假设的C实现与某些抽象机器的行为相同,还必须包含所需的文档
是的,一个C实现(不只是一个编译器——包括标准库、链接和运行时支持,和/或用于实现C的任何其他工具),它产生与一致性抽象机器一致的可观察行为1。本标准中的所有其他要求和段落不仅仅是额外的。它们定义了抽象机器的行为,因此它们有助于描述可观察的行为必须是什么
是的,一个没有可观察行为的程序可以优化为一个只返回的程序。请注意,xor eax,eax
在技术上是不需要的。然而,这可能只是标准中的一个无意缺陷,而不是目的
笔记
1规范要求的不仅仅是程序的行为。例如,实现还必须记录各种实现定义的行为。因此,这个与某些抽象机器行为相同的假设C实现还必须包含所需的文档。是的,您是对的。编译器可以做它想做的事情,只要可观察的行为与抽象机器可以产生的行为相同。但这本身并不是戏剧性的:为什么我们会关心一些无法观察到的事情?这就是优化编译器的要点
例如:
int main() {
int a;
for (int i=INT_MAX; i>=0; i--) {
a = i;
}
printf("%d\n", a);
return 0;
}
唯一可观察到的行为是它一次打印0
。因此,编译器可以优化循环以产生与以下相同的结果:
int main() {
printf("%d\n", 0);
return 0;
}
从本质上讲,这意味着不能使用空循环来添加延迟,因为它们可以被优化,完全不产生延迟
如果允许编译器假设程序中不会出现未定义的行为,那么最显著的副作用就是
第二个例子:
int main() {
struct {
int a[16];
int b[16];
} s;
for (i=0; i<16; i++) {
s.a[i] = i;
s.b[i] = 2 * i;
}
for (i=0; i<32; i++) {
printf(" %d", s.a[i]); // UB array access past upper bound
}
printf("\n");
return 0;
}
intmain(){
结构{
INTA[16];
int b[16];
}s;
对于(i=0;i是的,你是对的。编译器可以做它想做的事情,只要可观察到的行为与抽象机器可以产生的行为相同。但这本身并不引人注目:我们为什么要关心无法观察到的事情?这是优化编译器的重点
例如:
int main() {
int a;
for (int i=INT_MAX; i>=0; i--) {
a = i;
}
printf("%d\n", a);
return 0;
}
唯一可以观察到的行为是,它一次打印0
。因此,编译器可以优化循环以产生与以下相同的结果:
int main() {
printf("%d\n", 0);
return 0;
}
从本质上讲,这意味着不能使用空循环来添加延迟,因为它们可以被优化,完全不产生延迟
如果允许编译器假设程序中不会出现未定义的行为,那么最显著的副作用就是
第二个例子:
int main() {
struct {
int a[16];
int b[16];
} s;
for (i=0; i<16; i++) {
s.a[i] = i;
s.b[i] = 2 * i;
}
for (i=0; i<32; i++) {
printf(" %d", s.a[i]); // UB array access past upper bound
}
printf("\n");
return 0;
}
intmain(){
结构{
INTA[16];
int b[16];
}s;
对于(i=0;iFrom):“本国际标准中的语义描述描述了与优化问题无关的抽象机器的行为。”为了符合该标准,必须遵循“抽象机器”的“语义描述”。以及该“抽象机器”的“语义描述”是规范的其余部分,我不知道