【问题标题】:What sense do these clobbered variable warnings make?这些被破坏的变量警告有什么意义?
【发布时间】:2011-12-05 00:44:23
【问题描述】:

我有这样的功能:

#include <setjmp.h>
jmp_buf buf;
void func2(int g);
extern int some_global;
void func(int x)
{
    if (setjmp(buf))
        return;
    if (some_global)
        x += 5;
    func2(x);
}

GCC (gcc (Debian 4.4.5-8) 4.4.5) 给出警告:

test.c:在函数“func”中: test.c:5:警告:参数“x”可能被“longjmp”或“vfork”破坏[-Wclobbered]

为什么????我的意思是,显然我不在乎 x 是否被破坏,因为它不可能在 setjmp 返回后使用。考虑到它某种setjmp的特殊知识,即使是编译器也应该意识到一些如此明显的东西。

我的主要兴趣是在我继承的代码库中发现错误,因此,“改用这种编码风格”不是我要寻找的建议。然而,这里有许多奇怪的曲折。例如,如果x 是一个局部变量而不是一个参数,那么 GCC 不会抱怨。此外,如果没有if (some_global) 行,GCC 也不会抱怨。好的。有什么东西打乱了 GCC 的流量分析,或者 GCC 知道一些我不知道的东西。

所以,

  • 是否有一种简单的方法可以抑制此函数的警告,就像将未使用的参数强制转换为 (void) 一样?

  • 或者我只是在项目范围内禁止警告?

  • 还是我错过了什么?

更新:让我与您分享一个略有不同但不会产生警告的版本:

#include <setjmp.h>
jmp_buf buf;
void func2(int g);
extern int some_global;
void func(int y)
{
    int x = y;
    if (setjmp(buf))
        return;
    if (some_global)
        x += 5;
    func2(x);
}

【问题讨论】:

  • 我认为编译器不够聪明。在启用所有警告并将其视为错误的编译时,我不得不使用 MSVC++ 解决一些类似的问题。编译器有时可以说些什么是件好事,因为它可以为其他比我们知识渊博和幸运的人节省一些时间。
  • 我的 gcc (4.5.2) 只有在使用 -Wextra 时才会抱怨(引入 -Wclobbered)。你在使用任何一个标志吗?
  • @Hasturkun:看来你自己已经回答了你的问题。
  • 我没有收到 gcc 4.6.1 的警告。可能是特定于版本的问题。
  • @DietrichEpp:我问是因为-Wuninitialized 被记录为生成类似的警告,尽管我无法让 gcc 生成该消息

标签: c gcc warnings setjmp


【解决方案1】:

来自man longjmp

自动变量的值在调用后未指定 longjmp() 如果它们满足以下所有条件:

   ·  they are local to the function that made the corresponding setjmp(3)
      call;

   ·  their  values  are  changed  between  the  calls  to  setjmp(3)  and
      longjmp(); and

   ·  they are not declared as volatile.

碰巧,您在第一个示例中的 x 变量符合条件:

  • 它是函数的局部变量,因为函数参数就像局部自动变量一样。
  • 如果some_global 为真,它的值可能会在setjmp 之后更改。
  • 它不是易变的。

所以它的值可能是未指定的(破坏)。

关于为什么第二个版本不发出警告......不知道。

【讨论】:

  • 您似乎没有阅读我的问题。我明确表示我不在乎 x 是否被破坏,因为在 setjmp 返回后不会使用它。我想知道是否有办法在本地抑制警告。
【解决方案2】:

在网上搜索了一下,重新阅读了 GCC 文档后,我发现了这个:

功能属性:

returns_twice

returns_twice 属性告诉编译器一个函数可能返回不止一次。编译器将确保在调用此类函数之前所有寄存器都已失效,并将发出有关在函数第二次返回后可能被破坏的变量的警告。此类函数的示例是 setjmpvfork。此类函数的类似longjmp 的对应项(如果有)可能需要使用noreturn 属性进行标记。

所以看来 GCC 对setjmp 没有任何“特殊知识”,它只是暗示它有。它所知道的是setjmp 返回两次,而不是它总是第一次返回 0 而之后返回非零。天哪,那就太好了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-02-08
    • 2020-01-08
    • 1970-01-01
    • 2011-03-07
    • 1970-01-01
    • 1970-01-01
    • 2013-06-25
    相关资源
    最近更新 更多