我有一个有点大的项目,我发现有人添加了一些类似于下面的代码:
std::cout << std::hex << variable << endl;
除了浏览所有 cout 调用并手动查看每个调用之外,有没有办法确定哪个有问题的 cout 行以十六进制的形式离开了输出流的底部?
似乎有许多不同的方法来设置基础,因此在单个函数调用上设置断点似乎不起作用。 例如:
-
... << std::hex << ...
-
... << setbase(16) << ...
-
std::cout.setf ( std::ios::hex, std::ios::basefield );
- 等。
有没有快速的方法可以告诉我内部libstdc++使用哪个变量来存储基本变量,以便我可以在其上设置数据断点?
更新:
在玩弄代码之后,我终于能够部分使用perreal和Employed T俄语的答案提出解决方案。 这是我所做的:
首先,我在程序中添加了以下代码,以便我可以中断并单步执行函数以获取 cout 标志变量 (_M_flags( 的地址。
std::ios_base::fmtflags f;
f = std::cout.flags();
我在第二行设置了一个断点并单步进入函数并得到了以下 libstdc++ 代码:
// [27.4.2.2] fmtflags state functions
/**
* @brief Access to format flags.
* @return The format control flags for both input and output
*/
fmtflags
flags() const
{ return _M_flags; }
不幸的是,gdb 无法打印出这个变量,但通过进入反汇编视图,我能够查明_M_flags使用的地址:
x0x84ca2e8 <std::ios_base::flags() const> push %ebp
x0x84ca2e9 <std::ios_base::flags() const+1> mov %esp,%ebp
x0x84ca2eb <std::ios_base::flags() const+3> mov 0x8(%ebp),%eax
>x0x84ca2ee <std::ios_base::flags() const+6> mov 0xc(%eax),%eax
x0x84ca2f1 <std::ios_base::flags() const+9> pop %ebp
x0x84ca2f2 <std::ios_base::flags() const+10> ret
0xc(%eax)
包含_M_flags的地址。
在我得到地址后,在其上设置一个条件硬件观察点以查看十六进制位何时更改并跟踪有问题的代码是相当简单的。
事实证明,在运行时通过 dlopen 加载的 .so 对象是罪魁祸首。
我最终使用了此问题所引用的 Boost IO 状态保护程序来解决问题。
有没有快速的方法可以告诉我 glibc 内部使用哪个变量来存储基本变量,以便我可以在其上设置数据断点?
不:glibc 是一个C
库,对std::cout
一无所知,这是一个C++
构造。你的问题是关于libstdc++
,而不是关于glibc。
查看libstdc++实现,您似乎希望在std::cout._M_os._M_flags
上设置一个观察点。但是,由于在输出操作期间多次设置标志中的各种位,因此您可能希望将观察点设置为_S_hex (== 1<<3 == 8)
位的条件。
#include <iostream>
int main() {
std::ios_base::fmtflags f;
f = std::cout.flags();
std::cout << 21 << std::endl;
std::cout << (f & std::cout.hex) << std::endl;
std::cout << std::hex << 21 << std::endl;
f = std::cout.flags();
std::cout << (f & std::cout.hex) << std::endl;
return 0;
}
输出
21
0
15
8
因此,您似乎可以使用f & std::cout.hex
作为表达式或找出该标志在std::cout
中的存储位置,这可能取决于实现。