Motive: Passing struct to functions such as we can change it in any function and retrieve any value in any function.
I picked up this code from: http://cboard.cprogramming.com/c-programming/126381-passing-structure-reference-through-4-functions.html#post942397
I tweaked it a little and here it is:
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;
}
It works as expected on **gcc version 4.4.3 on ubuntu
$ gcc -o struct struct_passing.c
$ ./struct
Before: same
inside f3 x: changed
After: changed
But on gcc version 4.2.1 on freebsd, I cannot retrieve the changed value of "bob->x". I do not get inside f3 x: changed
. I get garbage instead.
Why?
Everything looks just fine to me. It's always instructive to run a small sample program like this in the debugger, to see what's really happening. If you don't know gdb, now is a great time to start. I've created struct_passing.[ch] from your code, let's have a look:
[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]
Yup, same compiler. Compile for debugging:
[wes@eeegor ~/src]$ cc -g -o struct struct_passing.c
And run it:
[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"...
OK, we probably want to know what's happening from main() on, so...
(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) {
We'll mostly use (s)tep to step into functions, and (n)ext to step over functions we don't want to see the inside of, like printf(). We may also occasionally (p)rint something.
(gdb) n
main () at struct_passing.c:23
23 foo.x = "same";
We haven't yet executed this line, so if we look at foo, it will probably contain garbage:
(gdb) p foo
$1 = {x = 0x80482c5 "\203Ä\fÃ"}
Yup, as expected, x points to some garbage string. That's because foo, and by extension foo.x, got created on the stack in the main() function, and the stack just has whatever random junk was left around before.
(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
So we step into f1() and see that we have correctly passed the address of foo into the function. Notice how the gdb (p)rint function always knows the type of what it's printing? In this case, seeing the address of the structure isn't very useful, so:
(gdb) p *bob
$3 = {x = 0x804857c "same"}
Oh, good, the structure still looks like it should. Let's keep going until we change it:
(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";
Remember, we haven't executed line 5 yet, so "bob" should still be the same:
(gdb) p *bob
$6 = {x = 0x804857c "same"}
Yup, so let's execute line 5 and look again:
(gdb) n
6 }
(gdb) p *bob
$7 = {x = 0x8048563 "changed"}
So "bob" did get changed. Let's keep going and see if it's still changed up in 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;
So we got what we expected. At this point, we're about to return from main(), it's best to just let the debugger continue so you don't half to walk through the tail end of the C runtime startup code:
(gdb) c
Continuing.
Program exited normally.
(gdb) Quit
(gdb)
Let's exit the debugger and run it normally to make sure we get the same output. It would be really weird if we didn't...
(gdb) q
[wes@eeegor ~/src]$ ./struct
Before: same
inside f3 x: changed
After: changed
Oh, good, the stars are still shining. I'm not sure what happened in your case, let's try compiling as you did and run it:
[wes@eeegor ~/src]$ gcc -o struct struct_passing.c
[wes@eeegor ~/src]$ ./struct
Before: same
inside f3 x: changed
After: changed
So now, let's improve your bug report. Give us the output of 'uname -a', 'gcc -v', and 'ld -v' so we can find out exactly what system you're using. Also read the 'Joel on Software' article(s) about how to write a bug report. :)
In my opinion the code is perfectly legal and it should work...
I suspect the problem is related to how the optimizer of gcc 4.2.1 handles string constants.
You can try the following compilation command line, to check if this is true:
$ gcc -O0 -o struct struct_passing.c
I suggest also to try the following code variation, to see if you get a better result:
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;
}