(注:这是一个语言律师问题,我不是在指任何特定的编译器。)
编译器在什么情况下可以降低程序的时间复杂度?
在什么情况下(如果有的话)被认为是“可观察的行为”,为什么?
(例如,编译器是否可以将多项式时间程序合法地“降级”为指数时间程序?)
如果C和C ++中的答案不同,或者在它们的不同版本中不同,请解释其差异。
(注:这是一个语言律师问题,我不是在指任何特定的编译器。)
编译器在什么情况下可以降低程序的时间复杂度?
在什么情况下(如果有的话)被认为是“可观察的行为”,为什么?
(例如,编译器是否可以将多项式时间程序合法地“降级”为指数时间程序?)
如果C和C ++中的答案不同,或者在它们的不同版本中不同,请解释其差异。
operator <
” 或 X = “调用 std::swap
”。 - o11c代码的性能不被视为可观察行为,因此编译器在性能方面可能会向任何方向进行修改。实际上,出于实现质量(QoI)的原因,编译器不会降低程序的质量,但在某些情况下,QoI与性能无关。
编译器可以根据给定的标志为正在构建的程序添加调试工具(例如,在库实现中使用带检查的迭代器时通常会这样做)。
请注意,编译器会降低程序质量的简单答案有两个方面:当客户要求时,或者实现者不想让用户使用编译器时。
C标准中的5.1.2.3节表示:
本国际标准中的语义描述描述了一个抽象机器的行为,其中优化问题不相关。
在C ++标准的1.9 [intro.execution]中有类似的措辞。
两个标准都有相同的可观察行为定义:
符合规范的实现的最小要求是:
— 对易失性对象的访问严格按照抽象机器的规则评估。
— 在程序终止时,写入文件的所有数据都应与根据抽象语义执行程序的结果相同。
— 交互设备的输入和输出动态应按照7.21.3中指定的进行。这些要求的目的是使未缓冲或行缓冲的输出尽快出现,以确保提示消息实际上出现在程序等待输入之前。
这是程序的可观察行为。
因此,其他任何内容(例如for
循环的性能或对非易失性变量执行的读取/写入次数)都不被认为是可观察的,因此编译器没有相应的性能要求。
如果编译器想重新评估一个代码块100次(假设它没有可观察的副作用,只改变非易失性变量的状态),并检查每次获得相同的结果(不受宇宙射线或故障硬件影响),则标准允许这样做。
有人指出,标准并不限制C运行时的工作方式,只限制其可观察行为。例如,你完全可以拥有解释型或JIT编译的C。
考虑一个C实现,其中所有内存单元都存储在底层系统的链表中。指针是该链表中的索引。所有指针操作将像往常一样运行,但运行时必须在每次内存访问时迭代遍历该链表。所有常见算法都会突然增加一个额外的N因子,例如常见的空结束字符串操作。