Странное поведение с использованием передачи по ссылке / разыменования - PullRequest
1 голос
/ 25 марта 2019

Вот мой демонстрационный код:

#include <stdio.h>

#define WORK 0

typedef struct FooStruct {
    int x;
} FooStruct;

void setX(FooStruct *foo_ptr) {
    FooStruct foo = *foo_ptr;

    if (WORK) {
        foo_ptr->x = 10;
    } else {
        foo.x = 10;
    }
}

FooStruct makeFoo() {
    FooStruct foo = { 0 };

    setX(&foo);

    return foo;
}

int main(void) {
    FooStruct foo = makeFoo();

    printf("X = %d\n", foo.x);

    return 0;
}

Если для WORK задано значение 1, код выполняется должным образом и печатает «X = 10».

Однако, если для WORK установлено значение 0, вместо этого выводится «X = 0», или если FooStruct не инициализирован по умолчанию (т. Е. Измените FooStruct foo = {}; на FooStruct foo;), valgrind выдаст значение неинициализированная ошибка в строке printf.

Я уверен, что это связано с пробелом в моем понимании, но для меня две разные ветви РАБОТЫ должны по существу быть идентичными в работе, поэтому я не уверен, откуда исходит недоразумение.

Это скомпилировано с gcc 8.2.0 с / без valgrind с равными результатами.

=======================

EDIT:

Упрощенный пример:

#include <stdio.h>

#define WORK 0

void setX(int *x_ptr) {
    if (WORK) {
        *x_ptr = 5;
    } else {
        int x = *x_ptr;
        x = 5;
    }
}

int main(void) {
    int x = 0;
    setX(&x);

    printf("X = %d\n", x);

    return 0;
}

Ответы [ 2 ]

3 голосов
/ 25 марта 2019

В этой функции:

void setX(FooStruct *foo_ptr) {
    FooStruct foo = *foo_ptr;

    if (WORK) {
        foo_ptr->x = 10;
    } else {
        foo.x = 10;
    }
}

, foo является локальной переменной типа FooStruct.Следовательно, никакая модификация, которую выполняет функция foo, не производит никакого эффекта, видимого за пределами функции.

То, что foo инициализируется копией содержимого FooStruct, на которое указывает параметр foo_ptrне имеет значения.В частности, он не делает локальный foo функции псевдонимом для того, на что указывает foo_ptr.

С другой стороны, если функция изменяет объект, на который указывает foo_ptr, тоКонечно, это видно любому другому коду, который может видеть этот объект, прямо или косвенно.

3 голосов
/ 25 марта 2019

Код работает, как и ожидалось, когда вы #define WORK 0 тоже. Если вы устанавливаете элемент в копии структуры, вы не должны ожидать, что оригинал будет изменен.

У вас есть:

void setX(FooStruct *foo_ptr) {
    FooStruct foo = *foo_ptr;

    if (WORK) {
        foo_ptr->x = 10;    // Modify the structure pointed to by foo_ptr
    } else {
        foo.x = 10;         // Modify the local copy of the structure
    }
}

Поскольку вы создали MCVE ( Минимальный, завершенный, проверяемый пример - спасибо!), С измененной копией структуры в setX().

ничего не поделаешь.
...