C 编译器编译 i = i++; 是否合法?作为系统("rm -rf /");?
Is it legal for a C compiler to compile i = i++; as system("rm -rf /");?
未定义行为到底有多未定义?我读过声称各种 C 标准允许第一个未定义行为之后的所有行为实际上是任意的。你会看到人们说像 i = i++;
:
这样的语句有四个基本级别的未定义性
- "
i
可以是语句后的 i
或 i+1
。"
- "
i
可以在语句后保留 任何值。"
- 任何值都可能发生任何事情,或者执行可能会完全停止,但是编译
i = i++;
并带有特定的副作用,例如 system("rm -rf /");
是不符合规范的。
- 绝对有可能发生任何事情,包括
system("rm -rf /");
!我描述的触发快乐文件系统破坏编译器是 100% 符合的。
我认为答案不是 1,但它是哪一个(如果有的话)?如果答案取决于某个人引用了哪个特定的 C 标准,那么一组答案会很好。
编辑:linked possible duplicate isn't really the same question (it's more asking if the possibility of undefined behavior along one code path results in undefinedness regardless of the code path), but the answer to this question 直接指出答案是 4 —— 也就是说,未定义确实意味着标准对行为没有任何限制。我不确定为什么所有的反对票...
第二次编辑:second linked question also isn't a duplicate. It's simply asking about why a given statement is undefined (the answer of course being the subtleties of sequence points). Again, this question's 最佳答案直接回答了我的问题,尽管没有权威引用(与已接受的答案不同)。
"undefined behavior"官方定义为:
behavior, upon use of a nonportable or erroneous program construct or
of erroneous data, for which this International Standard imposes no
requirements
2 NOTE Possible undefined behavior ranges from ignoring the situation
completely with unpredictable results, to behaving during translation
or program execution in a documented manner characteristic of the
environment (with or without the issuance of a diagnostic message), to
terminating a translation or execution (with the issuance of a
diagnostic message).
就是这个意思。这一段背后没有任何秘密含义、歧义或 "holy truth"。
试图推理未定义的行为是毫无意义的练习,对程序员和编译器都是如此。对于程序员来说,当您可以修复错误和编写代码时,您正在浪费时间担心不可移植和错误的行为。对于编译器来说,不可能捕捉到每个未定义行为的实例:这等同于停机问题。这就是为什么它首先是未定义的行为。因为这将是不合理的限制,如果不是这样,无疑会使编译器编写者的工作变得更加困难或不可能。
这是一个简单且技术上非类比的示例。在 Brainfuck 中,规范中没有任何内容说明如何处理不平衡的括号。它将简化实现,基本上不检查平衡括号(更少的代码和逻辑),代价是程序看起来正常工作、工作不正常或出现段错误(即在空容器上执行操作)。
C 是一种复杂得多的语言。如果 C 中没有 "undefined behavior",规范可能有 1300 页长。
未定义行为到底有多未定义?我读过声称各种 C 标准允许第一个未定义行为之后的所有行为实际上是任意的。你会看到人们说像 i = i++;
:
- "
i
可以是语句后的i
或i+1
。" - "
i
可以在语句后保留 任何值。" - 任何值都可能发生任何事情,或者执行可能会完全停止,但是编译
i = i++;
并带有特定的副作用,例如system("rm -rf /");
是不符合规范的。 - 绝对有可能发生任何事情,包括
system("rm -rf /");
!我描述的触发快乐文件系统破坏编译器是 100% 符合的。
我认为答案不是 1,但它是哪一个(如果有的话)?如果答案取决于某个人引用了哪个特定的 C 标准,那么一组答案会很好。
编辑:linked possible duplicate isn't really the same question (it's more asking if the possibility of undefined behavior along one code path results in undefinedness regardless of the code path), but the answer to this question 直接指出答案是 4 —— 也就是说,未定义确实意味着标准对行为没有任何限制。我不确定为什么所有的反对票...
第二次编辑:second linked question also isn't a duplicate. It's simply asking about why a given statement is undefined (the answer of course being the subtleties of sequence points). Again, this question's 最佳答案直接回答了我的问题,尽管没有权威引用(与已接受的答案不同)。
"undefined behavior"官方定义为:
behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements
2 NOTE Possible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message).
就是这个意思。这一段背后没有任何秘密含义、歧义或 "holy truth"。
试图推理未定义的行为是毫无意义的练习,对程序员和编译器都是如此。对于程序员来说,当您可以修复错误和编写代码时,您正在浪费时间担心不可移植和错误的行为。对于编译器来说,不可能捕捉到每个未定义行为的实例:这等同于停机问题。这就是为什么它首先是未定义的行为。因为这将是不合理的限制,如果不是这样,无疑会使编译器编写者的工作变得更加困难或不可能。
这是一个简单且技术上非类比的示例。在 Brainfuck 中,规范中没有任何内容说明如何处理不平衡的括号。它将简化实现,基本上不检查平衡括号(更少的代码和逻辑),代价是程序看起来正常工作、工作不正常或出现段错误(即在空容器上执行操作)。
C 是一种复杂得多的语言。如果 C 中没有 "undefined behavior",规范可能有 1300 页长。