This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: [RFC] [patch] 'p->x' vs. 'p.x' and 'print object on'
On Mon, Jul 21, 2008 at 5:52 PM, Tom Tromey <tromey@redhat.com> wrote:
>>>>>> "Paul" == Paul Pluzhnikov <ppluzhnikov@google.com> writes:
>
> Paul> Long time GDB users are somewhat used to 'p->x' and 'p.x' meaning
> Paul> the same thing. But, as test case below demonstrates, they don't
> Paul> mean the same thing when 'set print object on' is in effect.
>
> FWIW, I like this. I was always confused when I printed an object and
> saw a field, but was then unable to print the field directly.
>
> However, I recall bringing this up once, in the distant past. Someone
> pointed out a difficulty with this approach: there might be one field
> 'x' that would be used with the declared type, but another field, also
> named 'x', that would be used with the actual type. So, this could
> potentially be confusing (albeit in an already confusing situation).
Thanks for bringing that up. I've modified the test case to have
a field 'y' in both the base and derived classes (attached at the
end), and the current situation is (IMHO) just as confusing before
the patch as it is after :(
Before patch (current behavior):
Breakpoint 1, fn (f=0x7fffffffe690) at print-obj.cc:16
16 return f->y;
(gdb) p *f
$3 = {_vptr.Foo = 0x400570, x = 1, y = 2}
(gdb) p f->y
$4 = 2
(gdb) p f.y
$5 = 2
(gdb) set print object on
(gdb) p *f
$6 = (Bar) {<Foo> = {_vptr.Foo = 0x400570, x = 1, y = 2}, y = 20, z = 30}
(gdb) p f->y
$7 = 20
(gdb) p f.y
$8 = 2
// f.y and f->y do not mean the same thing :(
(gdb) finish
0x0000000000400305 in main () at print-obj.cc:22
22 return fn(&b);
Value returned is $9 = 2
// Confusing: 'print f->y' says '20'; but 'finish' says '2'
After:
Breakpoint 1, fn (f=0x7fffffffe660) at print-obj.cc:16
16 return f->y;
(gdb) p *f
$1 = {_vptr.Foo = 0x400570, x = 1, y = 2}
(gdb) p f->y
$2 = 2
(gdb) p f.y
$3 = 2
// without "print object on" patch makes no difference
(gdb) set print object on
(gdb) p *f
$4 = (Bar) {<Foo> = {_vptr.Foo = 0x400570, x = 1, y = 2}, y = 20, z = 30}
(gdb) p f->y
$5 = 20
(gdb) p f.y
$6 = 20
// with "print object on" GDB is consistently treating f.y and f->y
// as the same expression.
(gdb) finish
0x0000000000400305 in main () at print-obj.cc:22
22 return fn(&b);
Value returned is $7 = 2
// Still confusing ...
> Maybe this can be documented or otherwise resolved.
Some other alternatives (hand-simulated):
A) Print both:
(gbd) p f->y
$14 = 2 (f->Foo::y)
$15 = 20 (f->Bar::y)
(gbd) p f.y
$16 = 2 (f->Foo::y)
$17 = 20 (f->Bar::y)
B) Print warning:
(gdb) p f.y
Warning: more than one field 'y' resulted from lookup in dynamic
type of 'f'; set 'print object off' to see the other 'y'.
$18 = 20
C) Do what the language does: lookup field 'x' in the static type,
and only try dynamic type if the first lookup failed:
(gdb) p f.y
$19 = 2
(gdb) p f->y
$20 = 2
// The other field still accessible:
(gdb) p f->Bar::y
$21 = 20
// Lookup in Foo fails; try Bar
(gdb) p f->z
$22 = 30
I think "C" is the least confusing alternative.
It may actually be good to do "C" independent of the 'print object'
setting.
> Also, IMO this patch could use an associated test case.
Yes, I just wanted to see what people think about this before
creating the test case.
Thanks again.
--
Paul Pluzhnikov
// test case
struct Foo {
int x, y;
Foo() : x(1), y(2) { }
virtual ~Foo() { }
virtual int method() = 0;
};
struct Bar : public Foo {
Bar() : y(20), z(30) { }
int method() { return 42; }
int y, z;
};
int fn(Foo *f)
{
return f->y;
}
int main()
{
Bar b;
return fn(&b);
}