GCC не может предупредить о неинициализированной переменной
В следующем коде есть переменная, которая может быть неинициализирована. Кажется, что gcc должен генерировать предупреждение, но это не так:
$ 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)
Любые подсказки о том, как получить GCC сообщить о неинициализированной переменной?
4 ответа
Похоже, вы не можете - увидеть этот отчет об ошибке. (И этот, который помечен как дублирование этого - у него такой же тестовый пример, как и у вас.) Поскольку похоже, что основной причиной ошибки является почти 10 лет, может показаться, что это не простая задача для решения, На самом деле, вторая ошибка, с которой я связался, имеет фразу "Никогда не будет исправлено" в обсуждении, так что это выглядит не очень хорошо.
Если это действительно важно для вас, Clang поймает этот с -Wsometimes-uninitialized
, который входит в -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.
Вам нужно включить оптимизацию какого-то вида. Например, скомпилируйте ваш пример с -O2, и появится предупреждение.
Поскольку для этого требуется анализ путей кода, а это довольно дорогое вычисление, GCC включает его только при запросе оптимизации кода.
Проблема в том, что gcc не может знать, что вы вызовете функцию с нулевым аргументом. В этом случае тот факт, что вы тестируете, может быть хорошим намеком на то, что вы собираетесь делать это иногда, но в общем случае гораздо сложнее. Рассматривать:
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;
}
Это была бы вполне разумная функция, чей интерфейсный контракт заключается в том, что вы передаете ей только 1, 2 или 3, и любое "неинициализированное" предупреждение в этом случае будет ложным и, таким образом, уменьшит отношение сигнал / шум компилятора. генерация предупреждений.
Я согласен, что было бы неплохо, если бы компиляторы давали лучшую диагностику для подобных вещей, но это нелегко, и предупреждения, которые могут иметь ложные срабатывания, всегда являются тонким балансом между беспорядочным кодом с обходными путями для предупреждений и неспособностью отлавливать ошибки.
uninitializedTest.c:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int result;
if(rand())
result = 1;
printf("%d\n", result);
return 0;
}
Вот несколько тестовых прогонов:
$ 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 равно 4.8 (также не обнаружено с помощью avr-gcc-4.4.5)
Похоже, у gcc-4.0 была возможность распознать проблему.
$ 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)
Так... это было специфичное для Apple дополнение, на которое они имеют лицензию? Или, может быть, именно поэтому Apple отходит от открытого исходного кода... Может быть, они исправили десятилетнюю ошибку, а сообщество gcc не приняло ее?