在我看来一切都很好。在调试器中运行一个像这样的小示例程序,看看到底发生了什么,总是很有启发性的。如果您不了解 gdb,那么现在是开始的好时机。我已经从你的代码中创建了 struct_passing.[ch],让我们看看:
[wes@eeegor ~]$ gcc -v
Using built-in specs.
Target: i386-undermydesk-freebsd
Configured with: FreeBSD/i386 system compiler
Thread model: posix
gcc version 4.2.1 20070719 [FreeBSD]
是的,相同的编译器。编译调试:
[wes@eeegor ~/src]$ cc -g -o struct struct_passing.c
然后运行它:
[wes@eeegor ~/src]$ gdb struct
GNU gdb 6.1.1 [FreeBSD]
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-marcel-freebsd"...
好的,我们可能想知道从 main() 开始发生了什么,所以...
(gdb) b main
Breakpoint 1 at 0x80484c0: file struct_passing.c, line 21.
(gdb) run
Starting program: /usr/home/wes/src/struct
Breakpoint 1, main () at struct_passing.c:21
21 int main(void) {
我们将主要使用 (s)tep 单步执行函数,使用 (n)ext 单步执行我们不想看到其内部的函数,例如 printf()。我们也可能偶尔 (p) 打印一些东西。
(gdb) n
main () at struct_passing.c:23
23 foo.x = "same";
我们还没有执行这一行,所以如果我们看一下 foo,它可能会包含垃圾:
(gdb) p foo
$1 = {x = 0x80482c5 "\203Ä\fÃ"}
是的,正如预期的那样,x 指向一些垃圾字符串。这是因为 foo 以及扩展名 foo.x 是在 main() 函数中的堆栈上创建的,而堆栈只是之前留下的任何随机垃圾。
(gdb) n
24 printf("Before: %s\n", foo.x);
(gdb) n
Before: same
25 f1(&foo);
(gdb) s
f1 (bob=0xbfbfec40) at struct_passing.c:18
18 f2(bob);
(gdb) p bob
$2 = (thing_t *) 0xbfbfec40
所以我们进入 f1() 并看到我们已经正确地将 foo 的地址传递给了函数。请注意 gdb (p)rint 函数如何始终知道它正在打印的类型?在这种情况下,查看结构的地址并不是很有用,所以:
(gdb) p *bob
$3 = {x = 0x804857c "same"}
哦,很好,结构看起来还是应该的。让我们继续,直到我们改变它:
(gdb) s
f2 (bob=0xbfbfec40) at struct_passing.c:14
14 f3(bob);
(gdb) p *bob
$4 = {x = 0x804857c "same"}
(gdb) s
f3 (bob=0xbfbfec40) at struct_passing.c:9
9 f4(bob);
(gdb) p *bob
$5 = {x = 0x804857c "same"}
(gdb) s
f4 (bob=0xbfbfec40) at struct_passing.c:5
5 bob->x = "changed";
记住,我们还没有执行第 5 行,所以“bob”应该还是一样的:
(gdb) p *bob
$6 = {x = 0x804857c "same"}
是的,所以让我们执行第 5 行并再看一遍:
(gdb) n
6 }
(gdb) p *bob
$7 = {x = 0x8048563 "changed"}
所以“bob”确实变了。让我们继续看看 main() 中是否还有变化:
(gdb) n
f3 (bob=0xbfbfec40) at struct_passing.c:10
10 printf("inside f3 x: %s\n", bob->x);
(gdb) n
inside f3 x: changed
11 }
(gdb) n
f2 (bob=0xbfbfec40) at struct_passing.c:15
15 }
(gdb) n
f1 (bob=0xbfbfec40) at struct_passing.c:19
19 }
(gdb) n
main () at struct_passing.c:26
26 printf("After: %s\n", foo.x);
(gdb) n
After: changed
27 return 0;
所以我们得到了我们的预期。此时,我们即将从 main() 返回,最好让调试器继续运行,这样你就不会半途而废地走过 C 运行时启动代码的尾部:
(gdb) c
Continuing.
Program exited normally.
(gdb) Quit
(gdb)
让我们退出调试器并正常运行它以确保我们得到相同的输出。如果我们不这样做,那就太奇怪了……
(gdb) q
[wes@eeegor ~/src]$ ./struct
Before: same
inside f3 x: changed
After: changed
哦,很好,星星还在发光。我不确定你的情况发生了什么,让我们尝试像你一样编译并运行它:
[wes@eeegor ~/src]$ gcc -o struct struct_passing.c
[wes@eeegor ~/src]$ ./struct
Before: same
inside f3 x: changed
After: changed
现在,让我们改进您的错误报告。给我们'uname -a'、'gcc -v'和'ld -v'的输出,这样我们就可以准确地找出你正在使用的系统。另请阅读有关如何编写错误报告的“Joel on Software”文章。 :)