GDB在c ++对象的构造函数中报告参数的错误地址

Jam*_*ese 6 c++ constructor gdb parameter-passing stdstring

我正在经历一个奇怪的行为,GDB将一个字符串作为参数传递给构造函数.代码工作正常,但是当我在调试器中单步执行时,GDB似乎认为我的参数位于不同的地址.有谁知道这里发生了什么?

这是我可以创建的最简单的程序来演示问题:

--(jwcacces@neptune)--------------------------------------------(/home/jwcacces)--
--$ nl gdb_weird.cpp
     1  #include <iostream>
     2  #include <string>
     3
     4  class C
     5  {
     6  public:
     7     C(std::string str)
     8     {
     9        std::string* str_ptr = &str;
    10        std::cout << "Address of str: " << &str << std::endl;
    11        std::cout << "Address in str_ptr: " << str_ptr << std::endl;
    12        std::cout << "Value of str: " << str << std::endl;
    13     };
    14  };
    15
    16  int main(int, char*[])
    17  {
    18     std::string s("Hello, World!");
    19     C c(s);
    20     return 0;
    21  }
Run Code Online (Sandbox Code Playgroud)

编译调试信息,无需优化.
注意,我在为x86,x64和mingw(x86)编译时看到了这个问题.
我没有尝试过其他架构.

--(jwcacces@neptune)--------------------------------------------(/home/jwcacces)--
--$ g++ -O0 -g -Wall -Wextra gdb_weird.cpp -m32

--(jwcacces@neptune)--------------------------------------------(/home/jwcacces)--
--$ g++ --version
g++ (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Run Code Online (Sandbox Code Playgroud)

现在,调试:

--(jwcacces@neptune)--------------------------------------------(/home/jwcacces)--
--$ gdb a.out
GNU gdb (Ubuntu/Linaro 7.3-0ubuntu2) 7.3-2011.08
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://bugs.launchpad.net/gdb-linaro/>...
Reading symbols from /home/jwcacces/a.out...done.

(gdb) br main
Breakpoint 1 at 0x80488ce: file gdb_weird.cpp, line 18.

(gdb) run
Starting program: /home/jwcacces/a.out

Breakpoint 1, main () at gdb_weird.cpp:18
18         std::string s("Hello, World!");

(gdb) next
19         C c(s);

(gdb) step
C::C (this=0xffffd74f, str=...) at gdb_weird.cpp:9
9             std::string* str_ptr = &str;
Run Code Online (Sandbox Code Playgroud)

这是奇怪的,当我尝试输出时str,我得到了垃圾:

(gdb) output str
{
  static npos = <optimized out>,
  _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>},
                                           <No data fields>},
                 _M_p = 0xffffd748 "\024\260\004\b\364\177\354\367\360\211\004\b\364\177\354", <incomplete sequence \367>
                }
}
Run Code Online (Sandbox Code Playgroud)

那么,GDB认为地址str是什么?

(gdb) output &str
(std::string *) 0xffffd734
Run Code Online (Sandbox Code Playgroud)

程序认为地址str是什么?

(gdb) next
10            std::cout << "Address of str: " << &str << std::endl;

(gdb) next
Address of str: 0xffffd748
11            std::cout << "Address in str_ptr: " << str_ptr << std::endl;

(gdb) next
Address in str_ptr: 0xffffd748
12            std::cout << "Value of str: " << str << std::endl;
Run Code Online (Sandbox Code Playgroud)

这真的很奇怪,程序认为str0xffffd748,但gdb认为它在0xffffd734
And,当你输出将在0xffffd748它正常工作的字符串对象.

(gdb) output *(std::string*)0xffffd748
{
  static npos = <optimized out>,
  _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, 
                                           <No data fields>
                                          },
                 _M_p = 0x804b014 "Hello, World!"
                }
}
Run Code Online (Sandbox Code Playgroud)

程序本身使用参数没有问题:

(gdb) next
Value of str: Hello, World!
13         };

(gdb) continue
Continuing.
[Inferior 1 (process 19463) exited normally]

(gdb) quit
Run Code Online (Sandbox Code Playgroud)

我已经尝试将构造函数参数的类型更改为int,struct,指针,但我无法重现这种古怪.
另外,我尝试将调试格式设置为-ggdb.

问题:

  • 这里发生了什么?
  • 为什么GDB说std::stringnpos成员被优化掉了(也许出库的优化),以及这是否有什么关系呢?
  • 在GDB认为的"对象"中str,_M_p成员指向实际位于0xffffd748的地址是巧合str吗?
  • 在这种行为发生的其他情况下?

---- WOAH,突破----
如果我将调试格式设置为-gstabs +,GDB将获得str正确的地址.
这是否意味着gdb调试格式无法正常工作?

Mel*_*nez 1

从任何帖子(https://gcc.gnu.org/ml/gcc/2001-04/msg01037.html)来看,在调试 C++ 时,-gstabs 或 -gstabs+ 似乎是正确的标志。我希望这能有所帮助。