放宽执行命令的规则
Relaxing rules for execution order
C和C++标准规定执行顺序必须严格遵循源指令顺序。编译器可以自由地按任何顺序计算指令中的子表达式,但不能对用分号或冒号分隔的指令进行重新排序。
例如,在指令中:
A = A + B * C + D * E;
编译器可能会选择在B*C之前执行D*E,或者在末尾添加A。
如果现在将相同的计算拆分为不同的指令:
int t1 = B * C;
t1 += D * E;
A += t1;
在这种情况下,编译器无法在B*C之后评估D*E。
一般来说,这类代码稍微慢一点,因为编译器无法优化特定硬件的CPU指令顺序。
我想做的是相反的事情。例如,如果展开循环的主体显示:
A[0] = B[0] * C[0];
A[1] = B[1] * C[1];
A[2] = B[2] * C[2];
A[3] = B[3] * C[3];
有没有办法告诉编译器,这四条指令可以按任何顺序求值,因为它们是在单独的数据上操作的?即使是一个不可移植的技巧也是受欢迎的。
C和C++标准规定执行顺序必须严格遵循源指令顺序。
不完全是。他们说,程序的可观察行为,即I/O操作和对易失性对象的访问,必须发生,就好像是这样。编译器仍然可以随心所欲地重新排序求值,前提是它不会改变程序的行为。只要你的赋值和乘法运算没有明显的副作用,你的代码就可以重新排序。
然而,当您使用指针或引用时,问题会更大。通常,编译器无法判断A
、B
和C
指向不同的内存区域,因此必须假设对A
的赋值可能会更改稍后使用的B
或C
值之一。因此,它无法重新排序评估。在C中,可以使用restrict
告诉编译器它们不重叠,但在标准C++中不存在这样的特性。(如果它们是数组,那么这不是问题,在这种情况下,编译器知道它们不重叠。)
编译器只需要应用"好像"规则。可观察的行为必须保持预期,但如果编译器能够得出结论,这些操作不会相互影响,则可以按任何顺序进行操作。
函数参数的求值顺序在C和C++中是未定义的。所以你可以这样做:
template<typename T> void f(T a, T b)
{
}
f( A[0] = B[0] * C[0], A[1] = B[1] * C[1] );
您可以使用逗号运算符。或者,如果目标平台是多核架构,则可以使用OpenMP。
A[0] = B[0] * C[0],
A[1] = B[1] * C[1],
A[2] = B[2] * C[2],
A[3] = B[3] * C[3];
第页。事实上,用逗号是不对的。因此,显式并行可能是一个答案。或者函数调用,如邻居应答。
这可能有效:
void eval_any_order(...) {}
eval_any_order(
A[0] = B[0] * C[0],
A[1] = B[1] * C[1],
A[2] = B[2] * C[2],
A[3] = B[3] * C[3]
);
编译器可能已经对它们进行了重新排序——只要结果相同,就可以。
- 从命令行c++发送文本文件名
- 如何使用 < 和 > 命令获取 c++ 中的输入和输出?
- 为cl.exe(Visual Studio代码)指定命令行C++版本
- 如何在OMNET++中指定与命令行参数组合的输出文件名
- 此代码是否违反一个定义规则
- 生成文件不对文件使用隐式规则
- 使用QProcess执行命令,并将结果存储在QStringList中
- 数组长度,为什么从命令行获取时不能使用它?
- 变量可能尚未初始化[MIRA 2012规则9.1,强制性]
- 如果用户输入无效,如何使用字符串变量-C++重复输入命令
- 静态结构和一个定义规则
- clang整洁10忽略了我的NOLINT命令
- 在子目录中使用target_sources()命令时用于单元测试(qtest)的项目结构
- 如何处理linux终端中带有负号(-)的C++中的命令行参数
- VS Code "command":"make"与终端窗口中的命令行"make"不同
- 使用VS Code和CMake Tools运行自定义命令
- 尽管遵循了规则,内存泄漏在哪里
- 链接器命令 - 没有为第三方库设定目标的规则
- 放宽执行命令的规则
- GNU Make -在规则/目标中设置shell命令输出中的MAKEFILE变量