4

我遇到了类似于以下合法的代码,尽管不是很聪明。在同一函数范围内同时使用相同名称的两个堆栈变量是合法的,但它可能会导致问题。(阅读:我只是浪费了半个小时调试这个)。在 VS2010 上的警告级别 4(最高级别),我希望它会抓住这种事情。我是否遗漏了一些东西,或者是时候用 lint 一次性访问整个代码库了吗?像 lint 这样的静态分析工具会不会出现这样的名称冲突?

   char *x = strchr(Buffer,' ');
   if (x)
   {
     *x = 0;
     x++;
     char *x = strchr(x,' ') 
     if (x)
        *x = 0;
   }
4

2 回答 2

2

编辑:当我写原始答案时(如下),我没有注意到这一点。您发布的代码是非法的,并导致未定义的行为。违规行是这一行:

char *x = strchr(x,' ');

这里的x调用strchr不是x封闭范围内定义的,而是x指在同一行之前定义的。因此,该行从未初始化的变量中读取,这会导致未定义的行为。根据 C++ 标准,

§3.3.2/1 [basic.scope.pdecl]
名称 的声明点紧接在其完整声明符(第 8 条)之后和其初始化程序(如果有)之前,除非下文另有说明。[ 例子:

   int x = 12;
   { int x = x; }

这里第二个 x 用它自己的(不确定的)值初始化。—结束示例]

如果下面示例中的相应行更改为,GCC 确实会抱怨

int x = 21 + x; // generates "warning: x is used uninitialized in this function"

strchr并在 VS2012 上复制您的示例会生成此警告(at/W1及以上):

warning C4700: uninitialized local variable 'x' used

原始答案如下(不完全准确):

代码没有任何违法之处。您通过添加大括号引入了一个新范围,并且您可以在新范围内定义变量,即使这些变量名称之前已在封闭范围中定义。

在新定义之后对变量的所有引用都将引用局部变量而不是封闭范围内的变量,直到局部变量的生命周期结束。即使使用以下代码编译,以下代码也不会在 GCC 上产生警告-pedantic -Wall -Wextra

#include <iostream>

int main()
{
  int x = 42;
  {
      std::cout << x << '\n';
      int x = 21;
      std::cout << x << '\n';
  }
  std::cout << x << '\n';
}

输出:

42
21
42

我不知道 lint 或其他静态分析工具是否会挑选出这些东西。这是合法的,但不可取。

于 2013-05-16T18:17:24.610 回答
2

PC-Lint会检测到这一点。以下代码:

main (int argc, char *argv []) 
{
    char *x = 0;
    if (x)
    {
        char *x = 0;
    }
}

发出警告:

main.cpp  6  Warning 578: Declaration of symbol 'x' hides symbol 'x' (line 3)
于 2013-05-16T18:41:48.793 回答