2013-05-16 170 views
4

我發現類似於下面的代碼是合法的,雖然不是很聰明。同一個函數中的兩個堆棧變量同時具有相同的名稱是合法的,但它可能會導致問題。 (閱讀:我只是浪費了半小時的時間來調試)。在VS2010(最高級別)的警告級別4上,我希望它能夠抓住這種事情。我是否錯過了一些東西,或者是時候用皮棉打造一次完整的代碼庫了?像lint這樣的靜態分析工具是否會像這樣發現名稱衝突?該代碼是否會導致警告

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

GCC做這個AFAIR更好... –

+0

它們是相同的範圍沒有。一個'x'是函數範圍,一個是塊範圍。 –

+0

我認爲這不容易引起警告。很多時候,這是人們想要的東西(例如,正式的參數名稱和類成員 - 通常你不想發明新的名字) – Ghita

回答

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) 
+1

弱規則。很多人都是這樣寫的。會有很多誤報。 – 2013-05-16 19:51:11

+1

@AndreyCpp仍然不是一個好主意。這條規則是MISRA的一部分是有原因的。同樣,這是我使用的所有靜態分析工具的常規檢查。看看這個鏈接:https://www.securecoding.cert.org/confluence/display/seccode/DCL01-C.+Do+not+reuse+variable+names+in+subscopes – Throwback1986

+0

挖掘我的副本的時間的PC-Lint再次。我曾經經常使用它,但已經習慣了, –

2

編輯:我沒有注意到這一點,當我寫了原來的答覆(見下文)。您發佈的代碼是非法的,並導致未定義的行爲。有問題的行是這樣的一種:

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

這裏strchr呼叫指在封閉範圍所限定的xx,而是在同一行前面定義的x。因此該行讀取未初始化的變量,這會導致未定義的行爲。從C++標準,

§3.3.2/ 1 [basic.scope.pdecl]
一個名字的點聲明的立即是其完整的說明符後(第8章)和其前初始化程序(如果有的話),除非如下所述。 [例如:

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

這裏第二個x用它自己的(不確定)值進行初始化。末端示例]如果在下面的示例中的相應行被改變爲

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

,複製上VS2012您strchr例如

GCC不抱怨生成此警告(在/W1及以上):

warning C4700: uninitialized local variable 'x' used 

原來的答案如下(不完全準確):

也沒什麼可說的代碼是非法的。您通過添加大括號來引入新範圍,並且您可以在新範圍內定義變量,即使這些變量名稱之前已在封閉範圍內定義過。

在新定義之後,所有對變量的引用都將引用局部變量而不是封閉範圍中的變量,直到本地變量的生存期結束。

42 
21 
42 

我不知道棉絨或其他靜態分析工具是否會要麼挑選出這樣的事情:即使與-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'; 
} 

輸出編譯下面的代碼產生的GCC沒有任何警告。這是合法的,但不可取。

+0

Yikes,你原來的答案其實是正確的,我的例子中的問題是無意的,但是感謝編輯答案。我會留下我的問題,疣和所有,因爲你的答案在這方面很有用。 –