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

将Derived不透明结构体传入void*函数后转成首个成员是否合法?

结论:这段代码不符合C语言标准,属于未定义行为,且逻辑完全错误

核心原因分析

你的代码混淆了「结构体首个成员的类型」和「成员指向的类型」,导致转换逻辑彻底错误:

  1. 结构体内存布局:struct Derived的首个成员是Base*类型的指针,而非Base结构体本身。这意味着Derived对象的起始地址处,存放的是一个指向Base结构体的指针值,而不是Base结构体的实际数据。
  2. 转换后的指针指向错误:
    • 当Derived* d被转成void* ptr传入函数后,ptr指向的是Derived对象的起始位置。
    • 强制转换(Base*)ptr得到的base指针,实际指向的是Derived对象内部的base成员(那个Base*变量)的内存地址,而非真正的Base结构体。
    • 调用base_set_first(base, 1)时,会把这个Base*变量的内存(原本是一个指针值)当成Base结构体的first成员来赋值,直接破坏了Derived对象里的指针,后续访问d->base会变成野指针,必然引发错误。

符合标准的正确做法

如果要通过void*传递Derived对象并操作其内部的Base结构体,正确的方式是先将void*转回Derived*,再访问其base成员:

void function(void *ptr)
{
    Derived *derived = (Derived*)ptr;
    base_set_first(derived->base, 1);
    //...
}

补充C标准相关规则

C标准允许将结构体指针转换为其首个成员类型的指针(注意是成员本身的类型,不是成员指向的类型):

  • 例如,如果struct Derived的首个成员是Base结构体(而非指针):
    struct Derived {
        Base base;
    };
    
    那么(Base*)&derived_obj是合法的,因为结构体的起始地址与首个成员的起始地址一致,这种转换符合C标准要求。

内容的提问来源于stack exchange,提问作者Florian Bailly

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 07:01:19