GDB показывает бессмысленные значения для членов класса, несмотря на рабочий код - PullRequest
0 голосов
/ 27 ноября 2009

Я столкнулся с (на мой взгляд) очень странной проблемой с gdb сегодня, пытаясь написать более C ++ -шишную версию метода reverse() моего строкового класса (конечно, для изучения). Несмотря на наличие правильного конструктора по умолчанию, который инициализирует все переменные-члены равными 0, они начинаются как тарабарщина внутри члена reverse() - в соответствии с gdb (все, кроме отладки, на самом деле работает отлично) - но не совсем Программа Bones, которая просто создает пустую строку. Может ли это быть как-то связано с тем, что reverse() является функцией-членом, которая создает экземпляр своего собственного класса? Если нет, то почему бы это не произошло в голой программе?

Кстати, прежде чем я упомяну какой-либо код: я компилирую таким образом:

g++ -c -o tests.o tests.cpp -Wall -Werror -DDEBUG=0 -O0 -ggdb3
g++ -c -o string.o string.cpp -Wall -Werror -DDEBUG=0 -O0 -ggdb3
g++ -o tests tests.o string.o -Wall -Werror -DDEBUG=0 -O0 -ggdb3

Код:

string::string() : buf(NULL), _length(0), _size(0) {
    init();
}

/* This is redundant in this case (right?), but the function is used elsewhere,
   and I added the above initialization list while debugging this. */
void string::init() {
    this->buf = NULL;
    this->_length = 0;
    this->_size = 0;
}

string string::reverse(void) const {
    string rev;
    rev.alloc(this->_length + 1);

    for (size_t i=0; i<this->_length; i++) {
    ...

Вот что я получу, запустив вышеизложенное через gdb 7.0 (в Linux):
(Извините за горизонтальную прокрутку, но это не имеет значения, поскольку вы все равно можете видеть все, что вам нужно.)

Breakpoint 1, exscape::string::reverse (this=0x7fffffffd580) at string.cpp:368
368                     string rev;
(gdb) next
378                     rev.alloc(this->_length + 1); <<<< not yet executed when we print below!
(gdb) p rev
$1 = {buf = 0x7fffffffd560 "", _length = 140737488344448, _size = 140737488344128}
(gdb) n
380                     for (size_t i=0; i<this->_length; i++) {
(gdb) 
381                             rev.buf[this->_length-i-1] = this->buf[i];
380                     for (size_t i=0; i<this->_length; i++) {
(gdb) p rev
$2 = {buf = 0x7fffffffd560 "P\321`", _length = 140737488344448, _size = 140737488344128}
(gdb) n
381                             rev.buf[this->_length-i-1] = this->buf[i];
(gdb) 
380                     for (size_t i=0; i<this->_length; i++) {
...
384                     rev._length = this->_length;
(gdb) 
386             }
(gdb) p rev
$3 = {buf = 0x7fffffffd560 "P\321`", _length = 140737488344448, _size = 140737488344128}
(gdb) next
main () at tests.cpp:72
(gdb) p r2 <<<< r2 is the name of the variable returned by reverse() of course
$4 = {buf = 0x60d150 "ABCDEF", _length = 6, _size = 7}

Почему переменные-члены в конечном итоге приводят к бессмысленным значениям в gdb? (Между прочим, значения тарабарщины всегда очень близки this! В этом запуске this == 0x7fffffffd580 == 140737488344448, то же значение, что и _length). Функция работает отлично, valgrind никогда не жалуется, и все хорошо ... пока я не попытаюсь переписать метод и не могу его правильно отладить, то есть.

Любой совет?

Обновление: пример программы, которая вызывает функцию:

#include <iostream>
#include "string.hpp"
int main() {
    exscape::string s("Hello, world!");
    exscape::string s2; // Use the default constructor
    s2 = s.reverse();
    std::cout << "Reversed: " << s2 << std::endl;

    return 0;
}

(gdb) break exscape::string::reverse
Breakpoint 1 at 0x402ed6: file string.cpp, line 368.
(gdb) run
Starting program: /home/serenity/programming/cpp/string/a.out 

Breakpoint 1, exscape::string::reverse (this=0x7fffffffdc80) at string.cpp:368
368                     string rev;
(gdb) n
378                     rev.alloc(this->_length + 1);
(gdb) p rev
$1 = {buf = 0x7fffffffdca0 "", _length = 140737488346240, _size = 140737488346208}
(gdb) finish
Run till exit from #0  exscape::string::reverse (this=0x7fffffffdc80) at string.cpp:378
0x000000000040163f in main () at bare.cpp:6
6               s2 = s.reverse();
Value returned is $2 = {buf = 0x607030 "!dlrow ,olleH", _length = 13, _size = 14}
(gdb) n
7               std::cout << "Reversed: " << s2 << std::endl;
(gdb) n
Reversed: !dlrow ,olleH

Обновление:

Я скопировал код на мой Mac и попытался отладить его там - работал как чудо:

Breakpoint 1, exscape::string::reverse (this=0x7fff5fbff800) at string.cpp:368
368         string rev;
(gdb) n
378         rev.alloc(this->_length + 1);
(gdb) p rev
$1 = (exscape::string &) @0x7fff5fbff7c0: {
  buf = 0x0, 
  _length = 0, 
  _size = 0
}

Однако эта версия GDB довольно древняя - «GNU GDB 6.3.50-20050815 (версия Apple, gdb-1344)».
Я попытался снизить Linux GDB до 6,8 и 6,6 безрезультатно. - Я тоже на самом деле пробовал 6.3, тоже не работает (и на совершенно не связанной ноте, похоже, что вкладка постепенно улучшалась с годами: -).

Ответы [ 2 ]

2 голосов
/ 15 ноября 2010

Думаю, проблема в том, что rev это возвращаемое значение?

Я не знаю причину, но попробуйте этот код: Если вы используете Test * p = & res;

и print & res и p в gdb, вы увидите, что два адреса различны, даже если вы выполните это с помощью -O0

#include <iostream>
#include <cstdlib>
#include <cstring>
using namespace std;


struct Test {
 int a;
 int b;
 int c;
 Test() : a(0), b(0), c(0) {}
 Test operator+(const Test &rhs) const;
};

Test Test::operator+(const Test &rhs) const
{
 Test res, nores;
 // cannot print the content of res (uninitialized), but nores is right.
 res.a = a + rhs.a;
 res.b = b + rhs.b;
 res.c = c + rhs.c;
 return res;
}
ostream &operator<<(ostream &out, const Test &a)
{
 out << a.a << ' ' << a.b << ' ' << a.c << endl;
}

int main()
{
 Test p1, p2;
 cout << p1 + p2 << endl;

 return 0;
}
0 голосов
/ 21 декабря 2009

Я предполагаю, что локальная переменная 'rev' не создается компилятором до тех пор, пока на нее нет ссылок (вполне нормальная оптимизация), и поскольку rev.alloc является первой ссылкой на локальную переменную, она не будет создана этот код выполняется.

Именно поэтому отладчик показывает неинициализированные данные перед вызовом rev.alloc. Я уверен, что если вы перейдете к этапу сборки, вы увидите, что если вы сможете интерпретировать сборку. В качестве альтернативы вы могли бы использовать «rev» перед вызовом «rev.alloc», и в этом случае я совершенно уверен, что когда вы остановитесь на «rev.alloc», вы увидите инициализированный локальный файл.

...