我有一个由调用者函数调用的被调用者函数,该函数修改联合中字段成员的内容。该联合嵌套在一个支柱内,并且该结构具有全局作用域。但是,对该特定字段的引用在语法上很长,因此我在调用者函数中声明了一个指向该字段的本地指针,以减少函数调用的冗长性。联合体封装在结构体中,结构体本身的结构如下:
typedef union
{
uint8_t data[8];
struct
{
uint32_t data_u32;
} PARAM_U32;
struct
{
float data_f;
} PARAM_FLOAT;
} EXAMPLE_UNION;
typedef struct
{
EXAMPLE_UNION member1;
EXAMPLE_UNION member2;
} EXAMPLE_STRUCT;
EXAMPLE_STRUCT global_example_struct;
void callee_func(uint32_t *pDataToModify, uint32_t newVal)
{
*pDataToModify = newVal;
}
void caller_func()
{
uint32_t *pMemberOfNestedUnionToModify = (uint32_t *)&EXAMPLE_STRUCT.member1.PARAM_U32.data_u32
uint32_t dummyNewVal = 0xFFFFFFFF;
callee_func(pMemberOfNestedUnionToModify, dummyNewVal);
}
当 callee_func() 直接尝试取消引用作为参数传入的指针时,会发生硬错误。这让我很困惑,因为虽然它是本地引用,但它引用了全局范围的数据。然而,当 callee_func() 仅将内存复制到指针时,操作成功并且字段被更新:
void callee_func(uint32_t *pDataToModify, uint32_t newVal)
{
// this works
memcpy((uint8_t *)pDataToModify, (uint8_t *)&newVal, 4);
}
为什么取消引用参数中传递的本地指针是无效的,但向其复制数据却是有效的?是否因为本地引用只是一个引用,仅指向全局范围数据的实例,因此没有分配堆栈空间来实际存储值?
您遇到的问题是由于您在
caller_func()
中引用全局结构实例的方式造成的。具体来说,您使用的是类型名称 EXAMPLE_STRUCT
而不是实际实例 global_example_struct
。
在您的代码中,您有:
uint32_t *pMemberOfNestedUnionToModify = (uint32_t *)&EXAMPLE_STRUCT.member1.PARAM_U32.data_u32;
这里,
EXAMPLE_STRUCT
指的是类型,而不是变量。尝试获取类型成员的地址是无效的,并会导致未定义的行为,在您的情况下,这会在取消引用时导致硬故障。
您应该引用全局实例
global_example_struct
而不是类型名称。这是更正后的行:
uint32_t *pMemberOfNestedUnionToModify = &global_example_struct.member1.PARAM_U32.data_u32;
通过此更改,您可以正确获取全局结构实例中
data_u32
的地址,并且在 callee_func()
中取消引用此指针应该可以正常工作,而不会导致硬故障。