C / C ++在最短的执行时间内提供任何保证吗?
为什么编译器似乎对没有任何作用的循环有礼貌,而不是消除它们?
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
优化级别。 我希望删除允许的空循环,从而在两个代码上获得相同的速度。
“花费的时间”是一个应该由编译器保存的副作用吗?
不,花费的时间不被视为可观察到的行为受到as-if规则的保护:
[C++14: 1.8/5]:
执行格式良好的程序的一致性实现应该产生与具有相同程序和相同input的抽象机器的相应实例的可能执行之一相同的可观察行为。 但是,如果任何这样的执行包含未定义的操作,则本国际标准不要求执行该程序的实现(即使在第一个未定义的操作之前的操作)。
[C++14: 1.5/8]:
一致性实现的最低要求是:
- 严格按照抽象机器的规则来评估对易失性对象的访问。
- 在程序终止时,写入文件的所有数据应该与根据抽象语义产生的程序执行的结果相同。
- 交互设备的input和输出dynamic将以这样一种方式进行,即在程序等待input之前提示输出实际上被传送。 什么构成交互设备是由实现定义的。
这些统称为程序的可观察行为 。 [注意:抽象语义和实际语义之间更严格的对应可以由每个实现来定义。 – 注意]
这些循环可以合法地进行优化,事实上,有些情况下,标准使得这种做法更加容易:
[C++14: 1.10/24]:
实现可能会假定任何线程最终都会执行以下操作之一:
- 终止,
- 拨打一个库的I / Ofunction,
- 访问或修改易失性对象,或
- 执行同步操作或primefaces操作。
[注意:这是为了允许编译器转换,例如删除空循环,即使无法证实终止。 – 注意]
你的编译器实际上可能是“礼貌”的,因为注意到这些程序中循环的意图似乎在减缓重复文本输出的发射。 🙂
你没有指定编译器,但我们假设它是gcc
。
gcc不删除空循环,至less不是根据文档 。 它包含以下文本:
从历史上看,GCC并没有删除“空”循环,假设你将一个程序放在程序中的最可能的原因是延迟,所以删除它们不会使真正的程序运行得更快。
但是,如果空循环被优化程序“清空”,则它可以删除空循环,也就是说,如果循环包含优化程序可以在循环之外移动的代码,则生成的循环为空。
从文档来看,在最新版本中这是否仍然是真实的。 该手册提到“历史”,没有说明为什么。 如果你用你的确切的平台和编译器的信息更新你的问题,也许可以给出更好的答案。
C或C ++可执行文件的执行时间不会很短 ,因为执行时间取决于许多特定于平台的问题,例如:
- 处理器时钟频率。
- 每个指令的时钟周期。
- 内部处理器执行优化。
- 中断。
- 处理器指令集/function。
一些处理器支持乘法,另一些则不支持。 不支持乘法的处理器比具有乘法指令的处理器花费更长的时间来执行程序。 与浮点相同。
处理器的内部运行速度各不相同。 时间测量有一个共同的单位称为“时钟周期”。 大多数处理器供应商在时钟周期中指定指令的持续时间。 由于内部支持(如高速cachingpipe理),此测量可能很困难。
一些处理器具有可以优化指令或指令模式的执行的逻辑。 一个优化是分支预测 。
许多平台都有中断。 例如,可能有一个“系统滴答”中断,它允许操作系统知道何时将执行切换到另一个程序。 有些不是那么周期性的,比如发生I / O时。 程序中断时,最小执行时间不能保证。
说明一个最小的执行时间将会破坏C和C ++语言的可移植性。 有些平台希望比最短时间更快地执行代码。 其他平台可能无法实现最短的执行时间(但是他们可以从像C这样的高级语言中受益)。
另外,如何衡量时间?
最小执行时间是否适用于延迟循环或轮询?
不,不保证:( N1570的报价,5.1.2.3程序执行 )
1本标准中的语义描述描述了优化问题无关的抽象机器的行为。
无论如何,C标准只规定了你的程序在抽象机器上执行的行为,抽象机器可以有无限的内存和/或CPU。