我听说过编译器优化。
例如:
时的那个while(myBool)
doStuff();
编译器知道你不在while循环中修改myBool,它只读取myBool一次并且不会每次都检查它。
这可能会受volatile
关键字影响吗?
所以我试图“欺骗”编译器,它认为价值没有改变。
int main()
{
struct st
{
int a;
int b; //I want to make difference by writing volatile here
}s;
s.b = 1;
while(s.b > 0)
{
*((&s.a)+1) = 0;
std::cout << "test" << std::endl;
}
}
但即使启用了完全优化(vs2012),这也不会欺骗编译器。这可能是非常蹩脚的伎俩:)
我怎么欺骗它?它甚至可能吗?
我的目标是创建简单的单线程程序,使用volatile
关键字打印“test”并打印无限次“test”而不使用关键字。
编辑:不幸的是我对汇编程序不好,所以如果内存读数首先被优化的话,我真的无法阅读:)
答案 0 :(得分:2)
您正在做的是未定义的行为。您无法通过写信s.b
来访问*((&s.a)+1)
,因为无法保证s.a
和s.b
之间没有任何填充字节。
如果你想强迫那里没有填充,请查看你的编译器选项。对于GCC / Clang,您将使用__attribute__((packed))
声明结构。对于MSVC,您可以使用#pragma pack
directive。
没有充分的理由使用该代码访问s.b
到s.a
。在这种情况下你真正应该做的是,假设你有充分的理由不直接访问s.b
,那就是使用一个数组(volatile
,如果需要的话)。保证数组在内存中是连续的,无需特殊的属性/编译指示。
此外,在某些情况下,编译器不会进行某些优化:如果i
是一个变量,并且您写入a[i]
,然后读取a[1]
,则编译器可以'假设a[1]
不只是写入,因此它无法将其缓存在寄存器中。如果您有两个不相关的变量a
和b
并且您写入*(&a+1)
然后从b
读取,则编译器将假设{ {1}}不只是写给。这是b
未定义行为的一个非常好的理由,因为它导致编译器做出不真实的假设并导致程序以奇怪的方式运行。
答案 1 :(得分:1)
我认为您在询问如何确保编译器假定值几乎相同(在您的示例中为true),因此compliler会优化此值。 如果您这样做,那么您正在寻找一组特定于编译器的关键字。 这是我在g ++中使用的
#define predict_true__(exp) __builtin_expect((exp), 1)
#define predict_true__(exp) (exp)
这样你可以做到
while ( predict_true__( myBool ))
doStuff() ;
myBool会有效运行。 希望它有所帮助,你会知道在使用视觉的情况下要看什么。
另外:我发现以下帖子谈到它。不过,我担心这是一个悲伤的话题:likely/unlikely equivalent for MSVC
答案 2 :(得分:0)
简短的回答是structs
不保证在记忆中是连续的。数组是。你无法像这样访问结构!
可能有帮助的问题:Pointer arithmetic for structs。它详细介绍了如何做到这一点及其原因。但总结一下,结构的字段之间可能有填充,也可能没有填充。我特别喜欢查理对这个问题的回答。