使用传递引用/取消引用的奇怪行为
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
指向的对象,那么当然可以直接或间接地看到该对象的任何其他代码。
这是我的演示代码:
#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
指向的对象,那么当然可以直接或间接地看到该对象的任何其他代码。