2

我听说过编译器优化。

例如,当:

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),这也不会欺骗编译器。这可能是非常蹩脚的把戏:)

我该如何欺骗它?甚至可能吗?

我的目标是创建简单的单线程程序,它使用使用的关键字打印“test”,volatile并在没有关键字的情况下打印无限次的“test”。

编辑:不幸的是我不擅长汇编程序,所以如果首先优化内存读取,我真的无法阅读:)

4

3 回答 3

2

你正在做的是未定义的行为。您无法s.b通过写入来访问,*((&s.a)+1)因为无法保证s.a并且s.b它们之间没有任何填充字节。

如果您想强制没有填充,请查看您的编译器选项。对于 GCC/Clang,您可以使用__attribute__((packed)). 对于 MSVC,您将使用#pragma pack指令

没有充分的理由s.b通过s.a使用该代码进行访问。在这种情况下,假设您有充分的理由不s.b直接访问,您真正应该做的是使用数组(volatile如果需要的话)。数组保证在内存中是连续的,不需要特殊的属性/编译指示。

此外,在某些情况下,编译器不会进行某些优化:如果i是一个变量并且您写入到a[i]后跟读取a[1],编译器不能假设它a[1]不是只是写入的,所以它不能将其缓存在寄存器中。然而,如果您有两个不相关的变量ab并且您写入*(&a+1)然后从中读取b,编译器假定这b不仅仅是写入。这是未定义行为的一个很好的原因*(&a+1),因为它会导致编译器做出不真实的假设并导致您的程序以奇怪的方式运行。

于 2012-08-30T18:58:27.610 回答
1

我认为您在问如何确保编译器假定该值几乎相同(在您的示例中为 true),因此编译器会针对该值进行优化。如果你这样做了,那么你正在寻找一组编译器特定的关键字。这就是我在 g++ 中使用的

#define predict_true__(exp)     __builtin_expect((exp), 1)
#define predict_true__(exp)       (exp)

这样你就可以做到

while ( predict_true__( myBool ))
    doStuff() ;

它将有效运行,因为 myBool 是真的。希望它有所帮助,并且您将知道在使用视觉的情况下该看什么。

补充:我发现下面的帖子谈到了它。不过,恐怕这是一个悲伤的谈话:可能/不太可能等同于 MSVC

于 2012-08-30T18:47:09.460 回答
0

简短的回答是structs不能保证在内存中是连续的。数组是。你不能像那样访问结构!

一个可能有帮助的 SO 问题:structs 的指针算法。它更详细地介绍了您如何不能做到这一点以及为什么。但总结是结构的字段之间可能有也可能没有填充。我特别喜欢查理对这个问题的回答。

于 2012-08-30T19:00:19.853 回答