这是我的演示代码:
#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;
}
答案 0 :(得分:3)
当您#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()
中修改后的结构副本没有任何作用。
答案 1 :(得分:3)
在此功能中:
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
指向的对象,那么对于任何其他可以直接或间接看到该对象的代码,当然都是可见的。