2013-07-17 33 views
13

Đoạn mã sau có một biến có thể chưa được khởi tạo. Dường như gcc phải tạo cảnh báo nhưng không phải là:gcc không cảnh báo biến không được khởi tạo

$ cat a.c 
int foo(int b) { 
    int a; 
    if (b) 
    a = 1; 
    return a; 
} 

$ gcc-4.7 -c -Wall -Wmaybe-uninitialized -o a.o ./a.c 
$ gcc-4.7 -v 
Using built-in specs. 
COLLECT_GCC=gcc-4.7 
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.7/lto-wrapper 
Target: x86_64-linux-gnu 
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.7.3-2ubuntu1~12.04' --with-bugurl=file:///usr/share/doc/gcc-4.7/README.Bugs --enable-languages=c,c++,go,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.7 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.7 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --with-system-zlib --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu 
Thread model: posix 
gcc version 4.7.3 (Ubuntu/Linaro 4.7.3-2ubuntu1~12.04) 

Bất kỳ manh mối nào về cách để gcc báo cáo biến chưa được khởi tạo?

+0

Bất kỳ cơ hội nào trình biên dịch đủ thông minh để thấy rằng b được đặt là luôn luôn khác 0 ở nơi khác? –

+0

@MichaelDorgan, có * là * không có mã nào khác trong ví dụ của OP. –

+0

Không hiểu điều đó. Tôi giả định rằng không có "chính" được xác định, phải có mã khác ... –

Trả lời

10

Có vẻ như bạn không thể - xem this bug report. (Và this one, được đánh dấu là bản dupe của nó - nó có một trường hợp thử nghiệm giống hệt với của bạn.) Vì có vẻ như lỗi gốc đã gần 10 năm, có vẻ như đây không phải là vấn đề dễ giải quyết. Trong thực tế, lỗi thứ hai mà tôi liên kết có cụm từ "Không bao giờ cố định" trong cuộc thảo luận, vì vậy điều đó không tốt.

Nếu nó thực sự quan trọng với bạn, clangkhông bắt này với -Wsometimes-uninitialized, được bao gồm với -Wall:

a.c:3:7: warning: variable 'a' is used uninitialized whenever 'if' condition is 
     false [-Wsometimes-uninitialized] 
    if (b) 
    ^
a.c:5:10: note: uninitialized use occurs here 
    return a; 
     ^
a.c:3:3: note: remove the 'if' if its condition is always true 
    if (b) 
    ^~~~~~ 
a.c:2:8: note: initialize the variable 'a' to silence this warning 
    int a; 
    ^
     = 0 
1 warning generated. 
+0

Clang (phiên bản 3.0) của tôi không nhận dạng '-Wsometimes-uninitialized' hoặc' -Wmaybe-uninitialized'. Tôi đã có thể tạo ra các cảnh báo được hiển thị ở trên với -Wconditional-uninitialized hoặc -Weverything. – clandau

+1

Clang 3.0 khá cũ. –

4

Vấn đề là gcc không thể biết bạn sẽ gọi hàm với một đối số bằng không. Trong trường hợp này, thực tế là bạn đang thử nghiệm có thể là một gợi ý tốt mà bạn có ý định đôi khi làm như vậy, nhưng trường hợp chung là khó khăn hơn nhiều. Xem xét:

int foo(int b) { 
    int a; 
    switch(b) { 
    case 1: 
    a = 1; 
    break; 
    case 2: 
    a = 0; 
    break; 
    case 3: 
    a = 2; 
    break; 
    } 
    return a; 
} 

Đây sẽ là một chức năng hoàn toàn hợp lý có hợp đồng giao diện là bạn chỉ vượt qua 1, 2, hoặc 3 với nó, và bất kỳ "chưa được khởi tạo" cảnh báo sẽ trong trường hợp đó là giả mạo, và do đó làm giảm tỷ lệ tín hiệu trên tạp âm của thế hệ cảnh báo của trình biên dịch.

Tôi đồng ý sẽ tốt hơn nếu trình biên dịch đưa ra chẩn đoán tốt hơn cho những thứ như thế này, nhưng không dễ, và cảnh báo có thể có dương tính giả luôn là hành động cân bằng tinh tế giữa mã lộn xộn với cách giải quyết cảnh báo và không bắt lỗi.

+0

Đây chính là ví dụ được đưa ra trong [cẩm nang gcc] (http://gcc.gnu.org/onlinedocs/gcc-4.4.7/gcc/Warning-Options.html) tại mục nhập cho '-Wuninitialized'. Như nó nói ở đó, "những cảnh báo này được thực hiện tùy chọn" vì lý do đó. Rõ ràng, đó là sai, và không có tùy chọn để có được cảnh báo. – clandau

+1

Trong những trường hợp này, tôi vui vẻ chấp nhận một cảnh báo sai, được gọi là cảnh báo giả mạo, đặc biệt là khi tôi đã bật '-Wuninitialized' hoặc' -Wall' một cách rõ ràng. Tốt hơn nhiều so với tất cả các từ khóa phủ định sai hiện tại (nghĩa là không có cảnh báo khi có một). Có thể cho rằng, nếu một trình biên dịch không thể xác định được nó một cách đáng tin cậy, thì không thể nào một con người đáng tin cậy, vì vậy biến nên có một trình intialiser. –

1

uninitializedTest.c:

#include <stdio.h> 
#include <stdlib.h> 


int main(void) 
{ 
    int result; 
    if(rand()) 
     result = 1; 

    printf("%d\n", result); 

    return 0; 
} 

Dưới đây là một vài thử nghiệm chạy:

$ avr-gcc -Os -Wuninitialized -o uninitializedTest uninitializedTest.c 
$ gcc-4.2 -Os -Wuninitialized -o uninitializedTest uninitializedTest.c 
$ gcc-4.0 -Os -Wuninitialized -o uninitializedTest uninitializedTest.c 
uninitializedTest.c: In function ‘main’: 
uninitializedTest.c:32: warning: ‘result’ may be used uninitialized in this function 

$ gcc-4.2 -Os -Wmaybe-uninitialized -o uninitializedTest uninitializedTest.c 
cc1: error: unrecognized command line option "-Wmaybe-uninitialized" 
$ gcc-4.2 -Os -Wuninitialized -o uninitializedTest uninitializedTest.c 
$ gcc-mp-4.8 -Os -Wuninitialized -o uninitializedTest uninitializedTest.c 
$ gcc-mp-4.8 -Os -Wmaybe-uninitialized -o uninitializedTest uninitializedTest.c 

avr-gcc là 4,8 (Cũng không bị phát hiện với avr-gcc-4.4.5)

Có vẻ như gcc-4.0 có khả năng nhận ra vấn đề.

$ gcc-4.0 -v 
Configured with: /var/tmp/gcc/gcc-5493~1/src/configure --disable-checking -enable-werror --prefix=/usr --mandir=/share/man --enable-languages=c,objc,c++,obj-c++ --program-transform-name=/^[cg][^.-]*$/s/$/-4.0/ --with-gxx-include-dir=/include/c++/4.0.0 --with-slibdir=/usr/lib --build=i686-apple-darwin9 --program-prefix= --host=powerpc-apple-darwin9 --target=powerpc-apple-darwin9 
Thread model: posix 
gcc version 4.0.1 (Apple Inc. build 5493) 

Vậy ... đó có phải là một bổ sung cụ thể của Apple mà họ có giấy phép không? Hoặc có lẽ đó là lý do tại sao Apple đã chuyển từ nguồn mở ... Có thể họ đã sửa một lỗi đã có từ một thập niên và cộng đồng gcc không chấp nhận nó?

1

Bạn cần bật tối ưu hóa một số loại. Biên dịch lại ví dụ của bạn bằng -O2, và cảnh báo sẽ xuất hiện.

Vì điều này đòi hỏi phải phân tích các đường dẫn mã và nó là một tính toán khá tốn kém, GCC chỉ cho phép nó khi được yêu cầu tối ưu hóa mã.

+0

Điều này làm việc cho tôi. Thật không may là tôi không thể có được hành vi này mà không có -O2. –

Các vấn đề liên quan