我碰巧挖掘C并锁定自由编程。摆弄它我想知道gcc能给我一个保证程序执行方式与我写下来完全相同的方式,并且在某个步骤中没有执行寄存器优化,并且其顺序中没有改变操作。
正如我目前所理解的那样,它保证了内存操作以完全相同的顺序发生,并且方法调用以及它们自身和内存操作以相同的顺序发生。在重新排序之间可能会发生。
可以使用volatile关键字关闭寄存器优化。
是否有任何其他保证或角落案件C和特别是gcc暗示的?
答案 0 :(得分:3)
编译器只需要不改变程序的含义。
程序的含义由其C语句的语义给出,例如volatile
限定符是一种在语义级别上与外部代理交互的方法。
然而,单独volatile
在线程同步方面没用,它只有本地效果。
所以你应该只暗示C的标准意味着什么,如果标准没有给出语句的排序语义,也没有任何副作用,那么就没有了。
为了优化某些代码,编译器必须证明优化不会改变含义。
这通常是一个困难(甚至是不可判定的)问题,所以它只在简单的上下文中完成。
考虑
#include <stdio.h>
int simple(const int a, const int b)
{
int c = a + b; //3x Memory operation?
int d = c*c; //2x Memory operation?
return d+d; //Memory operation?
}
int main()
{
int a = 0; //Memory operation?
int b = 0; //Memory operation?
a = simple(2, 3); //Function call + Memory operation?
b = simple(3, 4); //Function call + Memory operation?
printf("%d %d\n", a, b); //Function call + 3x Memory operation?
return 0;
}
C标准规定a = simple(2, 3);
在b = simple(3, 4);
之前执行,因为表达式的结尾是序列点。
这是gcc使用完全优化生成的代码
lea 0x18f0(%rip),%rcx # 0x100403030, "%d %d\n"
mov $0x62,%r8d
mov $0x32,%edx
callq 0x100401110 <printf>
我使用了cygwin,因此ABI是Windows的一部分。这相当于
printf("%d %d\n", 50, 98);
这是一个临时示例,函数simple
纯并且编译时常量表达式,因此结果在编译时已知。<登记/>
这证明了gcc需要优化通话。
在编写无锁代码时,只要您使用正确的语义(例如volatile
)将读写访问作为副作用,就不必担心编译器优化仅限优化)。
我真正应该担心的是memory ordering,正如我的评论所指出的那样。
C11最终在其memory model中修复了所有这些内容。
答案 1 :(得分:1)
如果您的代码依赖于不重新排序操作而不进行任何其他优化,那么它只是&#34;未定义的行为&#34;。
如果您搜索此类保证,则只需搜索保证您编写执行正确的损坏程序。您应该使用由您使用的语言表示的语义。如果您需要假设语言如何在给定的操作系统和机器上实现操作,那么您完全走错了路线!
如果您确实对实际的编译器版本和使用的底层操作系统有某种保证,则无法保证该功能!所以措辞&#34;保证&#34;也不是真的。如果必须简单的答案是:根本没有保证!该语言具有语义,编译器保证实现它。根本不是更多!。
答案 2 :(得分:1)
C中线程之间的顺序保证只能通过C11中的streetAddress.matches()
或特定于编译器的扩展来实现。在所有其他情况下,编译器需要保证的唯一事情是程序的外部可见行为(这可以大致转换为:函数调用和不在编译器控件下的内存引用)与根据标准。从C语言的角度来看,C11线程之前并不存在,所以它并不关心线程行为。