g++ 在不优化变量的情况下显示未初始化变量的警告
g++ Show warnings for uninitialized variables without optimizing out variables
我有以下要调试的示例程序:
#include <iostream>
#include <assert.h>
using namespace std;
int f(int x) {
assert(false); // something bad happens
return 2 * x;
}
int main() {
int a;
for (int i = 0; i < 5; i++) {
a++; // a is uninitialized
cout << a << endl;
}
cout << f(1) << endl;
}
这段代码有两个问题:
- 循环内的变量
a
未初始化
- 函数
f
导致程序崩溃
为了检测这些问题,我使用 g++ -Wall -Og -g source.cpp
进行编译并收到以下警告:
source.cpp: In function ‘int main()’:
source.cpp:17:10: warning: ‘a’ may be used uninitialized in this function [-Wmaybe-uninitialized]
17 | a++; // a is uninitialized
|
如 问题所示,标志 -Og
(或任何其他优化标志)是获得此警告所必需的。
当我使用 gdb
调试生成的可执行文件时,它崩溃了(因为 assert 语句)并且回溯看起来像这样:
[...]
#4 0x000055555555528f in f (x=<optimized out>) at source.cpp:7
#5 0x0000555555555322 in main () at source.cpp:21
可以看到,变量x
已经被优化掉了。发生这种情况是因为 -Og
标志,如 问题中所述。
显然,我不想将其用于调试目的。但是当我删除 -Og
标志时,前面提到的警告将不再出现。我现在想找到一种无需优化变量即可获得此警告的方法。 g++
这可能吗?
我在 Ubuntu 20.10 上使用 g++
版本 10.2.0 和 gdb
版本 9.2。
Is this possible with g++?
没有。不幸的是,GCC 执行“使用的值是否未初始化?”在其中一个优化过程中进行分析,禁用优化也会禁用该过程。
将此与 Clang/LLVM 进行对比,后者的明确目标是 而不是 根据优化发出警告。
clang++ -Wall -Wextra -c t.cc # no optimization
t.cc:17:9: warning: variable 'a' is uninitialized when used here [-Wuninitialized]
a++; // a is uninitialized
^
t.cc:14:10: note: initialize the variable 'a' to silence this warning
int a;
^
= 0
1 warning generated.
As you can see, the variable x has been optimized out.
这是 g++
(如果它没有为参数发出位置信息)或 gdb
(如果它没有解码 g++
发出)。
理论上-Og
应该不会降低您的调试体验,尽管这里显然确实如此。
查看 readelf -wi
的 g++
编译代码,我看到:
<1><285d>: Abbrev Number: 114 (DW_TAG_subprogram)
<285e> DW_AT_external : 1
<285e> DW_AT_name : f
<2860> DW_AT_decl_file : 1
<2861> DW_AT_decl_line : 5
<2862> DW_AT_decl_column : 5
<2863> DW_AT_linkage_name: (indirect string, offset: 0x169d): _Z1fi
<2867> DW_AT_type : <0xe4f>
<286b> DW_AT_low_pc : 0x3d
<2873> DW_AT_high_pc : 0x23
<287b> DW_AT_frame_base : 1 byte block: 9c (DW_OP_call_frame_cfa)
<287d> DW_AT_GNU_all_call_sites: 1
<287d> DW_AT_sibling : <0x28e1>
<2><2881>: Abbrev Number: 115 (DW_TAG_formal_parameter)
<2882> DW_AT_name : x
<2884> DW_AT_decl_file : 1
<2885> DW_AT_decl_line : 5
<2886> DW_AT_decl_column : 11
<2887> DW_AT_type : <0xe4f>
<288b> DW_AT_location : 0x2dc (location list)
<288f> DW_AT_GNU_locviews: 0x2d8
...
我没有看到 0x2dc
或 0x2d8
的任何定义,所以在我看来这是 g++
方面的问题,但我不完全确定如何阅读位置列表。有可能 g++
实际上发出了所需的信息,而 GDB 没有按应有的方式解释它。
P.S。 lldb
显示与 GDB 相同的输出:
a.out: t.cc:7: int f(int): Assertion `false' failed.
Process 974666 stopped
* thread #1, name = 'a.out', stop reason = hit program assert
frame #4: 0x0000555555555205 a.out`f(x=<unavailable>) at t.cc:7:5
4
5 int f(int x) {
6
-> 7 assert(false); // something bad happens
8
9 return 2 * x;
10 }
这进一步表明问题可能出在 g++
方面。
我有以下要调试的示例程序:
#include <iostream>
#include <assert.h>
using namespace std;
int f(int x) {
assert(false); // something bad happens
return 2 * x;
}
int main() {
int a;
for (int i = 0; i < 5; i++) {
a++; // a is uninitialized
cout << a << endl;
}
cout << f(1) << endl;
}
这段代码有两个问题:
- 循环内的变量
a
未初始化 - 函数
f
导致程序崩溃
为了检测这些问题,我使用 g++ -Wall -Og -g source.cpp
进行编译并收到以下警告:
source.cpp: In function ‘int main()’:
source.cpp:17:10: warning: ‘a’ may be used uninitialized in this function [-Wmaybe-uninitialized]
17 | a++; // a is uninitialized
|
如 -Og
(或任何其他优化标志)是获得此警告所必需的。
当我使用 gdb
调试生成的可执行文件时,它崩溃了(因为 assert 语句)并且回溯看起来像这样:
[...]
#4 0x000055555555528f in f (x=<optimized out>) at source.cpp:7
#5 0x0000555555555322 in main () at source.cpp:21
可以看到,变量x
已经被优化掉了。发生这种情况是因为 -Og
标志,如
显然,我不想将其用于调试目的。但是当我删除 -Og
标志时,前面提到的警告将不再出现。我现在想找到一种无需优化变量即可获得此警告的方法。 g++
这可能吗?
我在 Ubuntu 20.10 上使用 g++
版本 10.2.0 和 gdb
版本 9.2。
Is this possible with g++?
没有。不幸的是,GCC 执行“使用的值是否未初始化?”在其中一个优化过程中进行分析,禁用优化也会禁用该过程。
将此与 Clang/LLVM 进行对比,后者的明确目标是 而不是 根据优化发出警告。
clang++ -Wall -Wextra -c t.cc # no optimization
t.cc:17:9: warning: variable 'a' is uninitialized when used here [-Wuninitialized]
a++; // a is uninitialized
^
t.cc:14:10: note: initialize the variable 'a' to silence this warning
int a;
^
= 0
1 warning generated.
As you can see, the variable x has been optimized out.
这是 g++
(如果它没有为参数发出位置信息)或 gdb
(如果它没有解码 g++
发出)。
理论上-Og
应该不会降低您的调试体验,尽管这里显然确实如此。
查看 readelf -wi
的 g++
编译代码,我看到:
<1><285d>: Abbrev Number: 114 (DW_TAG_subprogram)
<285e> DW_AT_external : 1
<285e> DW_AT_name : f
<2860> DW_AT_decl_file : 1
<2861> DW_AT_decl_line : 5
<2862> DW_AT_decl_column : 5
<2863> DW_AT_linkage_name: (indirect string, offset: 0x169d): _Z1fi
<2867> DW_AT_type : <0xe4f>
<286b> DW_AT_low_pc : 0x3d
<2873> DW_AT_high_pc : 0x23
<287b> DW_AT_frame_base : 1 byte block: 9c (DW_OP_call_frame_cfa)
<287d> DW_AT_GNU_all_call_sites: 1
<287d> DW_AT_sibling : <0x28e1>
<2><2881>: Abbrev Number: 115 (DW_TAG_formal_parameter)
<2882> DW_AT_name : x
<2884> DW_AT_decl_file : 1
<2885> DW_AT_decl_line : 5
<2886> DW_AT_decl_column : 11
<2887> DW_AT_type : <0xe4f>
<288b> DW_AT_location : 0x2dc (location list)
<288f> DW_AT_GNU_locviews: 0x2d8
...
我没有看到 0x2dc
或 0x2d8
的任何定义,所以在我看来这是 g++
方面的问题,但我不完全确定如何阅读位置列表。有可能 g++
实际上发出了所需的信息,而 GDB 没有按应有的方式解释它。
P.S。 lldb
显示与 GDB 相同的输出:
a.out: t.cc:7: int f(int): Assertion `false' failed.
Process 974666 stopped
* thread #1, name = 'a.out', stop reason = hit program assert
frame #4: 0x0000555555555205 a.out`f(x=<unavailable>) at t.cc:7:5
4
5 int f(int x) {
6
-> 7 assert(false); // something bad happens
8
9 return 2 * x;
10 }
这进一步表明问题可能出在 g++
方面。