我有一个关于编译器可能做的优化的问题。
下面的代码将说明问题(这是一个示例):
typedef struct test
{
short i;
} s_test;
int function1(char *bin)
{
s_test foo;
lock(gmutex);
foo.i = *(int*)bin * 8;
unlock(gmutex);
sleep(5);
//
// Here anything can happen to *bin in another thread
// an inline example here could be: *(volatile int *)bin = 42;
//
int b = foo.i + sizeof(char*);
return (b > 1000);
}编译器是否会将最后一行替换为
return ((*(int*)bin * 8 + sizeof(char*)) > 1000);发布于 2012-06-05 15:31:55
我不认为编译器会做这样的优化。
unlock(gmutex)这是函数,编译器不能假定在解锁函数中bin指向的值是否会改变。
例如,也许bin来自一个globe。因此,bin的优化不能跨越函数调用。
发布于 2012-06-05 15:45:21
您的示例不必要地复杂,因为您通过与声明的类型不同的类型读取bin。别名规则相当复杂,char甚至很特别,我不会对此发表评论。
假设您的声明为int* bin (因此您不必强制转换指针),编译器将无权在函数调用之间对语句进行重新排序,它们形成了所谓的序列点。在调用unlock之前和之后,*bin的值可能不同,因此它必须在调用之后加载值。
编辑:正如slartibartfast所指出的,对于这个参数,unlock必须是(或包含)函数调用,而不仅仅是一个由编译器解析成一系列操作的宏。
发布于 2012-06-05 16:38:52
正如我在直接回答中所说的:你的互斥体不会保护任何东西。*bin所指向的char数组可能会在int访问期间被修改,因此根据您的机器的不同,您甚至不会得到关于您想要访问的内存的一致视图。回到你的问题:编译器不会将源代码转换成你所设想的序列,但它很可能会产生机器语言,这种语言实际上会以你的源代码的方式运行。如果它能够检查函数lock、unlock和sleep (看起来像是宏),并且可以推断出对所涉及的内存位置没有副作用,并且对调用sleep()没有实现定义的含义,这将使临时(“缓存”,尽管标准不使用这个术语)值无效,那么它就有权生成一个像您给出的指令序列。C(直到C99)本质上是单线程的,编译器可以采用它想要的任何优化策略,只要代码的行为“就像”它将在理想的假设的C机器上运行一样。Jens提到的序列点在单线程条件下不会影响正确性:编译器可以在整个函数期间将foo放在寄存器中,甚至可以使用*bin指向的内存位置作为foo.i的别名,所以这段代码本质上是危险的(尽管我认为它不会在大多数编译器上表现出这种行为)。
https://stackoverflow.com/questions/10893148
复制相似问题