2012-01-24 56 views
6

GDB將一個字符串作爲參數傳遞給構造函數時,我正在經歷一個奇怪的行爲。 代碼工作正常,但是當我在調試器中單步執行時,GDB似乎認爲我的參數位於不同的地址。有人知道這裏發生了什麼嗎?GDB在C++對象的構造函數中報告錯誤的參數地址

這是我可以創建演示該問題的最簡單的程序:

--([email protected])--------------------------------------------(/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 } 

編譯調試信息,不進行任何優化。
請注意,我爲x86,x64和mingw(x86)編譯時看到此問題。
我還沒有嘗試過其他架構。

--([email protected])--------------------------------------------(/home/jwcacces)-- 
--$ g++ -O0 -g -Wall -Wextra gdb_weird.cpp -m32 

--([email protected])--------------------------------------------(/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. 

現在,調試:

--([email protected])--------------------------------------------(/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; 

這裏的怪事,當我嘗試輸出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> 
       } 
} 

那麼,是什麼GDB認爲str地址是什麼?

(gdb) output &str 
(std::string *) 0xffffd734 

那麼程序認爲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; 

這是很奇怪的,程序認爲str0xffffd748,但GDB認爲其在0xffffd734
而且,當你輸出字符串對象,這將是在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!" 
       } 
} 

而且程序本身使用參數HS沒問題:

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

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

(gdb) quit 

我試圖改變構造函數參數的類型爲int,一個結構,一個指針,但我無法重現怪異。
另外,我已經嘗試將調試格式設置爲-ggdb。

問題:

  • 這是怎麼回事嗎?
  • 爲什麼gdb會說std::stringnpos成員已經被優化(可能會優化出庫),這和它有什麼關係?
  • 在GDB認爲str_M_p成員指向0xffffd748的那個「對象」中,str實際上位於的地址恰好是巧合嗎?
  • 在這種情況下會發生什麼情況?

----哇,突破----
如果我調試格式設置爲-gstabs +,GDB得到的str正確的地址。
這是否意味着gdb調試格式無法正常工作?

+0

對我而言,最重要的是您的「正確」指針0xffffd748也顯示爲您的第一個打印語句中「無效」字符串的_M_p成員。所以也許gdb在指針指針和指針指向指針之間混淆了?順便說一句我只是簡單地說「這就是爲什麼你應該傳遞字符串作爲const-refs」不是一個合適的答案:p – araqnid

+0

字符串作爲常規參數傳遞很好(非限定值傳遞),只是gdb有問題用它。 是的,_M_p指針對我來說真的很奇怪。 –

+0

它必須與std :: string是一個函數參數有關 - 如果您將str分配給C :: C()中的另一個std :: string變量,然後在gdb中檢查第二個變量,那麼看起來很好,甚至儘管函數參數似乎對gdb是垃圾。 –

回答