微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

g++ 显示未初始化变量的警告而不优化变量

如何解决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; 

}

这段代码有两个问题:

  1. 循环中的变量 a 未初始化
  2. 函数 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
      |

this 问题所示,标志 -Og(或任何其他优化标志)是获得此警告所必需的。

当我使用 gdb 调试生成的可执行文件时,它崩溃了(因为 assert 语句)并且回溯看起来像这样:

[...]
#4  0x000055555555528f in f (x=<optimized out>) at source.cpp:7
#5  0x0000555555555322 in main () at source.cpp:21

如您所见,变量 x 已被优化。发生这种情况的原因是 -Og 标志,如 this 问题中所述。

显然,我不希望将其用于调试目的。但是当我删除 -Og 标志时,前面提到的警告将不再出现。我现在想找到一种无需优化变量即可获得此警告的方法g++ 可以做到这一点吗?

我在 Ubuntu 20.10 上使用 g++ 版本 10.2.0 和 gdb 版本 9.2。

解决方法

这可以用 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.

如您所见,变量 x 已被优化。

这是 g++(如果它没有发出参数的位置信息)或 gdb(如果它没有解码 {{1} } 发出).

理论上g++应该不会降低您的调试体验,尽管在这里显然会降低。

查看 -Ogreadelf -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++ 实际上确实发出了所需的信息,而 GDB 没有按应有的方式解释它。

附言g++ 显示与 GDB 相同的输出:

lldb

这额外表明问题可能出在 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 } 方面。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。