使用传递引用/取消引用的奇怪行为

Strange behaviour using pass-by-reference / dereferencing

这是我的演示代码:

#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 行上的值未初始化错误。

我确定这是由于我的理解存在差距,但对我来说,两个不同的 WORK 分支在操作上应该基本相同,所以我不确定误解来自何处。

这是用 gcc 8.2.0 with/without valgrind 编译的,结果相同。

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

编辑:

简化示例:

#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;
}

当您也 #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(Minimal, Complete, Verifiable Example — 谢谢!),setX().

中的结构修改副本没有做任何事情

在这个函数中:

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 指向的对象,那么当然可以直接或间接地看到该对象的任何其他代码。