Motive:将struct传递给函数,例如我们可以在任何函数中更改它并检索任何函数中的任何值。
我稍微调整了一下,现在是:
struct_passing.h
typedef struct thing {
char *x;
}thing_t;
struct_passing.c
#include <stdio.h>
#include "struct_passing.h"
void f4(thing_t *bob) {
bob->x = "changed";
}
void f3(thing_t *bob) {
f4(bob);
printf("inside f3 x: %s\n", bob->x);
}
void f2(thing_t *bob) {
f3(bob);
}
void f1(thing_t *bob) {
f2(bob);
}
int main(void) {
thing_t foo;
foo.x = "same";
printf("Before: %s\n", foo.x);
f1(&foo);
printf("After: %s\n", foo.x);
return 0;
}
它在ubuntu上的** gcc版本4.4.3上按预期工作
$ gcc -o struct struct_passing.c
$ ./struct
Before: same
inside f3 x: changed
After: changed
但是在freebsd上的gcc版本4.2.1上,我无法检索“bob-&gt; x”的更改值。我没有inside f3 x: changed
。我改为垃圾。
为什么?
答案 0 :(得分:8)
一切看起来都不错。在调试器中运行这样的小样本程序总是有益的,看看到底发生了什么。如果您不了解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) {
我们主要使用tep来进入函数,并且(n)ext来跳过我们不希望看到内部的函数,比如printf()。我们偶尔也会发现一些东西。
(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”文章。 :)
答案 1 :(得分:0)
在我看来,代码是完全合法的,它应该工作...... 我怀疑这个问题与gcc 4.2.1的优化器如何处理字符串常量有关。 您可以尝试以下编译命令行,以检查是否为真:
$ gcc -O0 -o struct struct_passing.c
我建议您尝试以下代码变体,看看您是否获得了更好的结果:
struct_passing.c
#include <stdio.h>
#include "struct_passing.h"
const char *same = "same";
const char *changed = "changed";
void f4(thing_t *bob) {
bob->x = changed;
}
void f3(thing_t *bob) {
f4(bob);
printf("inside f3 x: %s\n", bob->x);
}
void f2(thing_t *bob) {
f3(bob);
}
void f1(thing_t *bob) {
f2(bob);
}
int main(void) {
thing_t foo;
foo.x = same;
printf("Before: %s\n", foo.x);
f1(&foo);
printf("After: %s\n", foo.x);
return 0;
}