Все выглядит хорошо для меня. Всегда полезно запускать небольшую демонстрационную программу, подобную этой, в отладчике, чтобы увидеть, что на самом деле происходит. Если вы не знаете 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"}
Так что "Боб" изменился. Давайте продолжим и посмотрим, изменился ли он в 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» о том, как написать отчет об ошибке. :)