这是我的演示代码:
#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分支在操作上应该基本相同,所以我不确定误解的来源。
这是使用带有/不带valgrind的gcc 8.2.0编译的,结果相同。
=======================
编辑:
简化示例:
#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
指向的对象,那么当然可以直接或间接地看到任何其他可以看到该对象的代码。