C++ 如何防止编译器优化从未使用过的load to变量

C++ 如何防止编译器优化从未使用过的load to变量,c++,visual-c++,compiler-optimization,dead-code,seh,C++,Visual C++,Compiler Optimization,Dead Code,Seh,简介: 我正在尝试快速修复旧代码,并使用uu try MSVC扩展来检查某些ptr是否指向某个合法内存,或者*ptr是否会导致内存冲突(如果是这样,我将放弃对该ptr的处理)。 所以我写了这样的东西: bool checkIsPtrPointingToValidAddress(const void *ptr) { __try { auto cpy = *((int*)ptr); // force mem access... if ( (cpy ==

简介: 我正在尝试快速修复旧代码,并使用uu try MSVC扩展来检查某些ptr是否指向某个合法内存,或者*ptr是否会导致内存冲突(如果是这样,我将放弃对该ptr的处理)。 所以我写了这样的东西:

bool checkIsPtrPointingToValidAddress(const void *ptr)
{
    __try
    {
        auto cpy = *((int*)ptr); // force mem access...
        if ( (cpy ==42) && ((rand()+rand()+rand()+rand()+ rand()) == 1))
        {
            FILE* pFile = fopen ("tempdata.dat","w"); //... by unlikely but possible action
             fputs (" ",pFile);
             fclose (pFile);
        }
        return true;
    }
    __except(1)
    {
        return false;
    }

}
volatile auto copy1 = *((char*)ptr);  // using int* here could lead to aliasing violations, so better char in the general case..
volatile auto copy1 = *((char*)ptr);
if (copy1 != copy2) 
   throw std::exception("Cannot happen, but compiler cannot know this");
问题是,我强制mem访问的解决方案看起来很奇怪,很难看,而且我不确定它是否正确。另外请不要,我不能在整个项目上禁用优化,所以这不是一个选项。MSDN上pragma optimize的文档很糟糕,也就是说,不清楚“”是否禁用了该函数上的所有优化

首先,这是一个开始,因此您可能需要仔细考虑整个设计。但如果你被迫坚持下去,那么:

bool checkIsPtrPointingToValidAddress(const void *ptr)
{
    __try
    {
        auto cpy = *((int*)ptr); // force mem access...
        if ( (cpy ==42) && ((rand()+rand()+rand()+rand()+ rand()) == 1))
        {
            FILE* pFile = fopen ("tempdata.dat","w"); //... by unlikely but possible action
             fputs (" ",pFile);
             fclose (pFile);
        }
        return true;
    }
    __except(1)
    {
        return false;
    }

}
volatile auto copy1 = *((char*)ptr);  // using int* here could lead to aliasing violations, so better char in the general case..
volatile auto copy1 = *((char*)ptr);
if (copy1 != copy2) 
   throw std::exception("Cannot happen, but compiler cannot know this");
我们当然应该这样做。编译器无法消除读取或假定它们是相同的,因此必须执行代码。另一方面,假设没有线程问题或其他有趣的场景,我们知道这两次读取是相同的,因此不会引发异常

已添加

根据本标准的规则,对易失性对象的任何读取或写入均构成可观察的行为(也称为副作用),因此,即使满足以下条件也应足够:

volatile auto copy = *((char*)ptr);

这包括写入易失性对象
副本
,因此无法对其进行优化。

从对类似问题的回答中可以看出:

  • 编译器相关
  • 平凡的
我找到的最好的信息来源是这里的问题/答案:

在我看来,最合理的解释似乎是:

  • 静态分析(valgrind)、调试、重构
  • 对你的编译器使用一些技巧
  • 查看该答案中广告的商业解决方案
  • windowsapi已经发布

    BOOL WINAPI IsBadReadPtr(_In_ const VOID *lp,_In_ UINT_PTR ucb);
    BOOL WINAPI IsBadWritePtr(_In_ LPVOID lp, _In_ UINT_PTR ucb);
    

    您需要阅读备注部分,但您的案例可能足够简单,这些函数就足够了。不管怎样,备注部分在尝试自己处理不安全指针时给出了一些有用的建议。

    我认为这就是
    volatile
    关键字的作用。但是如果不使用它,死代码消除是否仍然会杀死该负载。。。它可以证明我不使用它。。。或者易失性语义要求发生加载?对
    易失性
    内存位置的写入是可观察的行为。所以简单地说,
    volatile auto copy=*((char*)ptr)足够好,可以防止对其进行优化。参见
    C++11[intro.execution]§8+§12
    @Angew您的意思是
    *((char*)ptr)=*((char*)ptr)?因为否则我在你的例子中看不到文字?这也应该行得通,尽管写操作通常比读操作更昂贵,所以不一定更好。问题是,即使在强制转换之后,是否也可以观察到只读。
    ptr
    ,即使在强制转换之后也是不可测的。而你正在阅读它。然后将读取的结果写入
    copy
    ,即
    volatile
    。所以这个写操作不能被优化掉(根据定义,之前读取它的值也不能)。@Angew-Ah我明白了,volatile也会以同样的方式应用于非指针(尽管volatile后面的比率没有)。很明显,这是一个错误,即使它仍然可以工作。想用这个更好的解决方案写下你自己的答案还是在这里更新这个?我认为你应该得到那里的代表。