передача указателя структуры на функции, не работающие - PullRequest
1 голос
/ 28 июля 2011

Мотив: передача структуры в функции, такие как мы можем изменить ее в любой функции и получить любое значение в любой функции.

Я взял этот код из: http://cboard.cprogramming.com/c-programming/126381-passing-structure-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;
}

Работает как положено на ** gcc версии 4.4.3 на ubuntu

$ gcc -o struct struct_passing.c 
$ ./struct
Before: same
inside f3 x: changed
After: changed

Но на gcc версии 4.2.1 на freebsd,Я не могу получить измененное значение "bob-> x".Я не получаю inside f3 x: changed.Вместо этого я получаю мусор.

Почему?

Ответы [ 2 ]

8 голосов
/ 04 августа 2011

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

0 голосов
/ 29 июля 2011

По моему мнению, код совершенно легален, и он должен работать ... Я подозреваю, что проблема связана с тем, как оптимизатор 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;
}
...