【发布时间】:2018-06-27 21:03:30
【问题描述】:
在将参数传递给函数时遇到了一个奇怪的问题。
参数是一个结构体,定义为:
#pragma pack(push,1)
typedef struct {
struct {
uint8_t opcode;
uint8_t type;
union {
uint8_t attr;
struct {
unsigned int reserved : 6;
unsigned int sequence : 2;
};
};
uint8_t bytes;
} header;
uint8_t payload[15];
} message_t;
#pragma pack(pop)
我有一个函数将这个结构声明为:
void func1(void) {
message_t response;
在这个函数中,我将它作为参数传递给另一个函数:
func2(response);
在func2 内我声明了另一个结构体,它被定义为:
#pragma pack(push,1)
typedef struct {
struct {
uint8_t op_code;
avneraIDs_t IDs;
uint8_t length;
} header;
uint8_t payload[30];
} frame_t;
#pragma pack(pop)
此结构在func2 中声明为:
frame_t frame;
所以现在我在func2 打电话给memcpy。
memcpy((uint8_t *)&response, frame.payload, (frame.header.length - 1));
我已经验证frame.header.length 等于 20,现在减 1 将复制超过 19 个字节的数据。 response 的宽度为 19 个字节,所以应该没问题。
执行memcpy后,我打印出response的内容,内容看起来是正确的。
返回func1后我再次打印response的内容。现在内容没了,又是空的。
所以我做的调试是在func1 的上下文中打印response 的地址位置,然后得到地址0x2000a470。
如果我在func2 的上下文中打印response 的地址位置,我会得到地址0x2000a484。
如果我打印从地址0x2000a484 开始的内存,我会看到应该在response 中的数据。
为什么response 的地址在我将它传递给另一个函数后立即更改?
还有一些额外的信息,我正在用 C 语言编写,使用 GCC 和 ST Arm Core MCU。
【问题讨论】:
-
我觉得这个代码太拼了,你能不能试试更连贯的minimal reproducible example?
-
response按值传递给func2.. -
注意:不要期望
union { uint8_t attr; struct { unsigned int reserved : 6; unsigned int sequence : 2; }; };以可移植的方式覆盖uint8_t和位字段。 -
"返回 func1 后......" - 这本身就说明了问题,没有看代码就无法确定。鉴于您使用
response的方式,该代码有希望工作的唯一方法是它是否是全局代码。您的代码中并非如此。您正在使用func2(response);,这意味着您将其按值提供给func2。调用者的参数将保持不变。通过地址将其传递给func2更改它以接受指针作为其形式参数。最后,将func2中的&response用法更改为简单的response,因为它已经是一个正确的指针了。 -
为了简化@WhozCraig 所说的,
func2()中的变量response是来自func1()的变量的副本。您对副本所做的更改不会影响原件。需要传递一个指针,才能得到引用传递的效果。
标签: c arguments parameter-passing memory-address memcpy