将结构指针传递给函数不起作用

发布于 2024-11-26 19:49:34 字数 1161 浏览 2 评论 0原文

动机:将结构传递给函数,例如我们可以在任何函数中更改它并在任何函数中检索任何值。

我从以下位置获取了此代码: http://cboard.cprogramming.com/c-programming/126381-passing-struct-reference-through-4-functions.html#post942397

我稍微调整一下,它是:

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->x”的更改值。我没有内部 f3 x: 已更改。我反而得到垃圾。

为什么?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

猛虎独行 2024-12-03 19:49:34

对我来说一切看起来都很好。在调试器中运行这样的小示例程序总是很有启发性的,以查看到底发生了什么。如果您不了解 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”文章,了解如何编写错误报告。 :)

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. :)

故事与诗 2024-12-03 19:49:34

在我看来,该代码是完全合法的,并且应该有效......
我怀疑这个问题与 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;
}

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文