任何最近的、体面的编译器都会对带有正确标志的此类代码发出警告。这里的一般建议是始终启用所有警告。
在 g++/clang 上使用 -Wall,在 MSVC (Visual C++) 上使用 /W4。
例如:
uninit.cpp:
int main()
{
int *ptr1;
*ptr1 = 100;
}
g++:
$ g++ -Wall uninit.cpp
uninit.cpp: In function ‘int main()’:
uninit.cpp:4:11: warning: ‘ptr1’ is used uninitialized in this function [-Wuninitialized]
4 | *ptr1 = 100;
| ~~~~~~^~~~~
叮当++:
$ clang++ -Wall uninit.cpp
uninit.cpp:4:6: warning: variable 'ptr1' is uninitialized when used here [-Wuninitialized]
*ptr1 = 100;
^~~~
uninit.cpp:3:14: note: initialize the variable 'ptr1' to silence this warning
int *ptr1;
^
= nullptr
1 warning generated.
如您所见,编译器甚至会提示您需要使用哪些标志来专门打开这个单一警告 (-Wuninitialized)。
即使打开了警告,也会生成一个可执行文件。如果您希望编译在遇到警告时失败,请添加-Werror:
g++ -Wall -Werror uninit.cpp
uninit.cpp: In function ‘int main()’:
uninit.cpp:4:11: error: ‘ptr1’ is used uninitialized in this function [-Werror=uninitialized]
4 | *ptr1 = 100;
| ~~~~~~^~~~~
cc1plus: all warnings being treated as errors
您再次看到编译器为您指出必须添加什么标志才能仅将这一特定警告转变为错误 (-Werror=uninitialized)。
为了更通用地处理潜在的无效内存访问,您可以使用地址清理器:
g++ -fsanitize=address,undefined -g uninit.cpp
运行程序时的输出:
$ ./a.out
uninit.cpp:4:11: runtime error: store to null pointer of type 'int'
AddressSanitizer:DEADLYSIGNAL
=================================================================
==191==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x562eab7b9255 bp 0x7ffc74f9a750 sp 0x7ffc74f9a740 T0)
==191==The signal is caused by a WRITE memory access.
==191==Hint: address points to the zero page.
#0 0x562eab7b9254 in main /home/someuser/uninit.cpp:4
#1 0x7ff1e1d6e0b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
#2 0x562eab7b912d in _start (/home/someuser/a.out+0x112d)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /home/someuser/uninit.cpp:4 in main
==191==ABORTING
这建立在额外的检查中,因此会带来性能成本;但是当出现更复杂的问题导致的访问问题时,它会在运行时警告您/停止程序
至于纠正此类错误,这取决于正确解决方案的上下文 - 没有适合每个用例的单一答案,除了通用 确保在使用指针之前对其进行初始化第一次。一个好的规则是总是在声明指针后直接初始化它们。这当然只会处理如上所示的简单问题,而不是指针有条件地设置为某个无效值的问题。使用一般的错误修复技术来解决这些问题;)
一般建议通常还包括尽可能避免使用原始指针。