为什么编译器似乎对没有做任何事情并且不消除它们的循环有礼貌?
C标准是否需要循环需要一些时间?
示例,以下代码:
void foo(void) {
while(1) {
for(int k = 0; k < 1000000000; ++k);
printf("Foo\n");
}
}
运行速度比这个慢:
void foo(void) {
while(1) {
for(int k = 0; k < 1000; ++k);
printf("Foo\n");
}
}
即使有-O3
优化级别。
我希望删除允许的空循环,从而在两个代码上获得相同的速度。
&#34;花费的时间&#34;应该由编译器保留的副作用?
答案 0 :(得分:43)
不,花费的时间不算作可以遵守as-if规则的可观察行为:
[C++14: 1.8/5]:
执行格式良好的程序的符合实现应该产生与具有相同程序和相同输入的抽象机器的相应实例的可能执行之一相同的可观察行为。 / strong>但是,如果任何此类执行包含未定义的操作,则此国际标准不要求使用该输入执行该程序的实现(甚至不考虑第一个未定义操作之前的操作)。
[C++14: 1.5/8]:
符合要求的实施要求最低:
- 严格按照抽象机的规则评估对volatile对象的访问。
- 在程序终止时,写入文件的所有数据应与根据抽象语义生成的程序执行的可能结果之一相同。
- 交互式设备的输入和输出动态应以在程序等待输入之前提示输出实际传送的方式进行。构成交互设备的是实现定义的。
这些统称为程序的可观察行为。 [注意:抽象语义和实际语义之间更严格的对应关系可能是由每个实现定义。 -end note]
这些循环可以合法优化,实际上,有些情况下标准会让故意尝试更轻松地做到这一点:
[C++14: 1.10/24]:
实现可能会假设任何线程最终会执行以下操作之一:
- 终止,
- 调用库I / O函数,
- 访问或修改易失性对象,或
- 执行同步操作或原子操作。
[注意:这是为了允许编译器转换,例如删除空循环,即使无法证明终止也是如此。 -end note]
您的编译器实际上可能会“注意”这些程序中的循环意图似乎在减慢重复文本输出的发射。 :)
答案 1 :(得分:28)
您没有指定编译器,但我们假设它是^deleteProject/(\w+)/?$
。
gcc 不删除空循环,至少不是根据documentation。它包含以下文本:
从历史上看,GCC没有删除“空”循环,假设你最有可能把一个放在程序中的原因是延迟,所以删除它们不会让真正的程序运行得更快。
然而,它可以删除空循环,如果它们被清空&#34;优化器,也就是说,如果循环包含优化器可以移出循环的代码,并且结果循环为空。
从文档中不清楚在最新版本中是否仍然如此。该手册提到了历史性的#34;没有说明原因。如果您使用有关您的确切平台和编译器的信息更新您的问题,可能会给出更好的答案。
答案 2 :(得分:7)
C或C ++可执行文件没有最短执行时间,因为执行时间取决于许多特定于平台的问题,例如:
有些处理器支持乘法,其他处理器则不支持。不支持乘法的处理器执行程序所需的时间比具有乘法指令的进程要长。与浮点相同。
处理器的内部运行速度各不相同。有一个共同的时间测量单位称为&#34;时钟周期&#34;。大多数处理器供应商在时钟周期中指定指令的持续时间。由于内部支持(例如缓存管理),此测量可能很困难。
某些处理器具有可以优化指令或指令模式执行的逻辑。一个优化是分支预测。
许多平台都有中断。例如,可能存在&#34;系统标记&#34;中断,允许操作系统知道何时将执行切换到另一个程序。有些不是那么周期性,例如I / O发生时。程序中断时无法保证最短执行时间。
说明最短执行时间会对C和C ++语言的可移植性造成严重破坏。某些平台希望比最短时间更快地执行代码。其他平台可能无法实现最短的执行时间(但它们可以从像C这样的高级语言中受益)。
另外,如何衡量时间?
最小执行时间是否适用于延迟循环或轮询?
答案 3 :(得分:4)
不,不能保证:(引自N1570, 5.1.2.3 Program execution)
1本国际标准中的语义描述描述 抽象机器的行为,其中优化问题 是无关紧要的。
无论如何,C标准只指定程序在抽象机器上执行时的行为,抽象机器可能有无限的内存和/或CPU。