You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

全局结构体嵌套联合成员的局部指针解引用修改与Memcpy方式的对比问询

全局结构体嵌套联合成员的局部指针解引用修改与Memcpy方式的对比问询

嘿,我仔细看了你这段没写完的代码和潜在的疑问,应该是想对比「用局部指针解引用修改全局嵌套结构体联合成员」和「用memcpy方式修改」的差异对吧?先帮你把代码补全修正,再好好唠唠这两种方式的门道~

先把你的代码补全修正

你原来的caller_func里有几个小语法错误,比如用了类型名EXAMPLE_STRUCT而不是全局变量名global_example_struct,还有指针声明少了分号、多余的强制转换,修正后的完整代码如下:

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 = &global_example_struct.member1.PARAM_U32.data_u32;
    callee_func(pMemberOfNestedUnionToModify, 0x12345678);
}

局部指针解引用修改的方式分析

这种方式在你的场景里是非常合适的,咱们拆解下:

  • 优势:
    • 语法简洁,用局部指针代替冗长的嵌套成员路径,让代码可读性提升不少,尤其是需要多次访问这个成员的时候
    • 性能拉满:本质上和直接写global_example_struct.member1.PARAM_U32.data_u32 = 0x12345678;完全一样,没有额外的函数调用或字节复制开销,就是直接对目标内存地址赋值
    • 意图明确:指针类型和目标成员类型完全匹配,看代码就知道是要修改这个uint32_t类型的成员
  • 注意事项:
    • 千万别搞错指针类型:如果指针类型和目标成员类型不匹配,会导致内存访问错误(比如用float去指向uint32_t成员,解引用的时候会按float的方式解析内存),不过在你的代码里,因为直接取的是PARAM_U32.data_u32的地址,本身就是uint32_t类型,连强制转换都不需要(你原来加的强制转换是冗余的,反而可能掩盖以后成员类型变更的问题)
    • 联合内存布局的问题:不过咱们是直接访问联合里明确声明的成员,编译器会保证这个成员的内存对齐是符合uint32_t要求的,不用担心对齐错误

memcpy方式的对比分析

如果换成memcpy的方式,代码大概是这样:

void caller_func()
{
    uint32_t newVal = 0x12345678;
    memcpy(&global_example_struct.member1.PARAM_U32.data_u32, &newVal, sizeof(newVal));
}

这种方式的特点:

  • 属于“通用字节复制”,不管目标类型是什么,直接按字节把数据搬过去
  • 在你的场景下完全是冗余操作:因为咱们明确知道目标是uint32_t类型,直接赋值的效率和可读性都比memcpy好
  • 适用场景:只有当你需要复制不确定长度的内存块、或者类型不兼容但需要保留字节布局的时候(比如把一个结构体的二进制数据复制到缓冲区,或者处理网络包的二进制数据),memcpy才有用武之地
  • 劣势:即使编译器会把小尺寸的memcpy优化成直接赋值,但代码意图不如指针赋值清晰,还多了一层函数调用的开销(虽然优化后可能没了)

总结建议

在你这个特定的场景里,局部指针解引用修改的方式完爆memcpy,不管是代码可读性、性能还是意图表达上都是最优解。memcpy在这里属于杀鸡用牛刀,完全没必要。

另外再提一句,如果你只是单次访问这个嵌套成员,其实连局部指针都可以不用,直接写callee_func(&global_example_struct.member1.PARAM_U32.data_u32, 0x12345678);就行,只有当你需要多次访问这个成员的时候,局部指针才会体现出简化代码的价值。

备注:内容来源于stack exchange,提问作者Elliott Goldstein

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.15 15:49:30