【问题标题】:Does C make a difference between compiling and executing a program?C 在编译和执行程序之间有区别吗?
【发布时间】:2016-01-01 15:25:20
【问题描述】:

如果一个表达式的求值导致 C 中未定义的行为,并且该表达式总是在程序执行时求值(例如,如果它出现在 main 的开头),如果实现拒绝它,它是否符合编译时间? C语言中编译/翻译程序和执行程序有区别吗?

我知道有 C 语言的解释器。C 标准如何处理这种差异?

示例(读取未初始化的本地)

int main() {
  int i;
  return i;
}

当运行它时,在执行的任何阶段(甚至在调用main 之前),程序都可以做一些有趣的事情。但是当我们甚至没有尝试运行它时,也会发生一些有趣的事情吗?它会导致编译器本身的缓冲区溢出吗?

【问题讨论】:

  • 就我而言,允许编译器在编译时静态拒绝未定义的行为——毕竟,语法错误是未定义的行为。
  • 如果没有这种表达的例子,这个问题似乎有点宽泛和模糊。
  • 您已在评论中回复了有关该问题的观点。最好用例子来改进问题
  • 未定义是,嗯,未定义。这是否意味着,正确地说,该标准甚至没有解决在这些情况下会发生什么?也许拒绝编译器是鼻恶魔可以采取的一种形式
  • @FUZxxl:不,语法错误明确不是未定义的行为。语法错误需要诊断。未定义的行为需要诊断。

标签: c language-lawyer


【解决方案1】:

来自 C11 草案:

3.4.3 未定义的行为

在使用不可移植或错误程序结构或错误数据时的行为,本国际标准对此没有要求

注意 可能的未定义行为范围从完全忽略具有不可预测结果的情况,到在翻译或程序执行期间以记录的方式表现 环境(无论是否发出诊断消息),终止翻译或执行(发出诊断消息)。

在(非规范性)注释中提到终止翻译是未定义行为的可能结果,因此显然不打算排除编译时影响。规范部分当然允许它——它允许任何事情。因此,如果在编译期间检测到未定义的行为,符合标准的编译器可以终止翻译。

另外,在$4 的一致性中

如果违反了出现在约束或运行时约束之外的“应”或“不应”要求,则行为未定义。未定义的行为在本国际标准中以“未定义的行为”一词或省略任何明确的行为定义来表示。这三者在重点上没有区别;它们都描述了“未定义的行为”。

在规范定义或一致性描述中,“翻译时间”和“执行时间”之间没有区别。未定义行为的不同“种类”之间没有区别。

此外,ouahCan code that will never be executed invoke undefined behavior? 中指出的Defect Report #109 在其响应中包含以下内容:

[...] 如果其求值会导致未定义行为的表达式出现在需要常量表达式的上下文中,则包含程序不是严格符合的。此外,如果给定程序的每一次可能执行都会导致未定义的行为,那么给定程序就不是严格符合的。

一个符合的实现不能仅仅因为该程序的某些可能的执行会导致未定义的行为而无法翻译一个严格符合的程序。 [...]

这表明如果编译器不能静态确定所有路径都导致未定义的行为,则编译器不能使翻译失败。

【讨论】:

  • 但是这里有一个不清楚的地方让我担心:存在影响翻译的未定义行为。例如,它表示标题名称:“如果字符 '、\、”、// 或 /* 出现在 分隔符之间的序列中,则行为未定义。”。您引用的句子中提到的后果仅指这种未定义的行为?这基本上就是我的怀疑所在。
  • 并且该注释的措辞表明翻译和执行之间可能存在一些差异(至少存在这两个不同的概念),因为“......在翻译过程中表现或程序执行..”
  • 它还说,例如,“翻译单元可以单独翻译,然后再链接以生成可执行程序。”。因此,似乎有一个不确定的参与者假设接收“可执行程序”并且可以不理会它或执行该程序。如果它不管它,评估就不会发生,所以 UB 也不会发生。规范在哪里排除了这种模型?
  • 作为另一个示例,必须接受以下程序并(如果执行)正确执行:int main(int argc, char **argv) { if(argc < 0 && argc >= 0) { int i; return i; } return 0; },因为永远不会评估 UB 表达式。
  • 重新发表您的第一条评论:UB 就是 UB。没有描述两个(或更多)类。第二条评论:我不同意,注释明确指出运行时和编译时的后果都是可能的。
【解决方案2】:

在 C11 标准第 3.7.1 节中,根据术语未定义的行为的定义:

未定义行为:在使用不可移植或错误程序结构或错误数据时的行为,本国际标准对此没有任何要求

2 注意 可能的未定义行为包括完全无视情况和不可预测 结果,在翻译或程序执行期间以文件的方式表现 环境(发布或不发布诊断消息),终止翻译或执行(发布诊断消息)

所以我猜你可以静态拒绝包含未定义行为的程序,即使它是有效的。

【讨论】:

  • 但是这里有一个不清楚的地方让我担心:存在影响翻译的未定义行为。例如,它表示标题名称:“如果字符 '、\、“、// 或 /* 出现在 分隔符之间的序列中,则行为未定义。”。您引用的句子中提到的后果仅指这种未定义的行为?这基本上就是我的怀疑所在。
  • 并且该注释的措辞表明翻译和执行之间可能存在一些差异(至少存在这两个不同的概念),因为“......在翻译过程中表现或程序执行..”
  • 翻译和执行之间的差异(在执行模型中存在并明确说明)并不意味着未定义行为的含义存在差异。无论如何,如果您被允许在翻译期间拒绝包含运行时未定义行为的程序,我认为没有任何理由不能针对翻译期间直接发生的未定义行为执行此操作,这将是一种反限制。
【解决方案3】:

如果实现在编译时拒绝它,它是否符合要求?

它可能会也可能不会。 C 标准在第 3.4.3 节中对此进行了说明:

C11:3.4.3 未定义的行为

  1. 使用不可移植或错误程序结构或错误数据时的行为,本国际标准对此没有要求

  2. 注意可能的未定义行为范围从完全忽略情况导致不可预测的结果,在翻译或程序执行期间以环境特征的记录方式表现(无论是否发布诊断消息),终止翻译或执行(发出诊断消息)

那么回答你的问题:它会导致编译器本身的缓冲区溢出吗?

可以。

【讨论】:

  • 问题不在于符合标准的编译器是否必须拒绝此类程序,而是符合标准的是否允许拒绝此类程序。
猜你喜欢
  • 2021-06-29
  • 2015-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-02
  • 2011-05-22
  • 2012-02-16
  • 1970-01-01
相关资源
最近更新 更多