不一致的警告:变量可能被'longjmp'或'vfork'破坏

bou*_*ika 7 c++ longjmp setjmp g++4.8

我大多说服自己,我遇到了一些g ++ 4.8.3错误,但我想我会首先问这个列表,因为我对setjmp/longjmp的经验很少.我将我的代码简化为以下foo.cxx:

#include <setjmp.h>
#include <string.h>

// Changing MyStruct to be just a single int makes the compiler happy.
struct MyStruct
{
    int a;
    int b;
};

// Setting MyType to int makes the compiler happy.
#ifdef USE_STRUCT
typedef MyStruct MyType;
#elif USE_INT
typedef int MyType;
#endif

void SomeFunc(MyType val)
{
}

static void static_func(MyType val)
{
    SomeFunc(val);
}

int main(int argc, char **argv)
{
    jmp_buf env;
    if (setjmp(env))
    {
        return 1;
    }

    MyType val;
#ifdef USE_STRUCT
    val.a = val.b = 0;
#elif USE_INT
    val = 0;
#endif
    // Enabling the below memset call makes the compiler happy.
    //memset(&val, 0, sizeof(val));

    // Iterating 1 or 2 times makes the compiler happy.
    for (unsigned i = 0; i < 3; i++)
    {
        // calling SomeFunc() directly makes the compiler happy.
        static_func(val);
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我用g ++ 4.8.3编译这段代码.对我来说有趣的是,当我定义USE_STRUCT时,编译失败但成功使用USE_INT.代码中有注释进一步表明如何使用USE_STRUCT使编译成功.编译仅在g ++的-fPIC选项中失败,但这是我环境中的必需参数.

要查看编​​译错误:

g++ -DUSE_STRUCT -Wextra -Wno-unused-parameter -O3 -Werror -fPIC foo.cxx
Run Code Online (Sandbox Code Playgroud)
foo.cxx: In function ‘int main(int, char**)’:
foo.cxx:26:5: error: variable ‘val’ might be clobbered by ‘longjmp’ or ‘vfork’ [-Werror=clobbered]
Run Code Online (Sandbox Code Playgroud)

但是使用简单的int就可以了:

g++ -DUSE_INT -Wextra -Wno-unused-parameter -O3 -Werror -fPIC foo.cxx
Run Code Online (Sandbox Code Playgroud)

有人可以向我解释为什么val可能会被破坏,如果它是一个结构但不是如果它是一个int?如编码中的注释所示,对结构进行编译的其他方法的任何见解都会成功吗?或者这是否指向编译器错误?

任何见解和评论都非常感谢.

sth*_*sth 5

setjmp()保存当前堆栈。由于它是在 的声明之前调用的val,因此该变量不会位于保存的堆栈中。

\n\n

之后setjmp(),变量被初始化,如果代码稍后跳回该setjmp点,变量将再次初始化,从而破坏旧变量。如果应该在旧实例上调用一个不平凡的析构函数,则这是未定义的行为(\xc2\xa718.10/4):

\n\n
\n

setjmp如果将andlongjmp替换为setjmpand会为任何自动对象调用任何重要的析构函数,则 / 调用对具有未定义的行为。longjmpcatchthrow

\n
\n\n

旧实例的析构函数可能不会被调用。我的猜测是,gcc 不会对原始类型发出警告,因为它们没有析构函数,但会对更复杂的类型发出警告,这可能会出现问题。

\n