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

结构体指针比较、成员裁剪操作及未定义行为技术咨询

先把代码格式化,方便查看:

int main() {
    typedef struct { int first; float second; } type;
    type whole = { 1, 2.0 };
    void * vp = &whole;
    struct { int first; } * shorn = vp;
    printf("values: %d, %d\n", ((type *)vp)->first, shorn->first);
    if (vp == shorn) printf("ptrs compare the same\n");
    return 0;
}

问题1:指针相等比较vp == shorn是否属于未定义行为?

完全不属于未定义行为,这个比较是符合C标准规定的:

  • 从语法约束来看,C标准(比如C17 §6.5.9)明确允许等式运算符的两个操作数一个是void*指针,另一个是指向任意对象类型的指针。这里vp是void*,shorn是指向匿名结构体的对象指针,满足合法比较的条件。
  • 从地址值的逻辑来看,结构体对象的起始地址必然和它的第一个成员的地址完全相同(C17 §6.7.2.1规定结构体的起始位置不会有匿名填充)。vp指向whole这个type类型的结构体,shorn是从vp转换而来的指针,它的地址值和vp完全一致,所以比较结果会是true,代码会输出ptrs compare the same。

问题2:初始化shorn指针的转换是否合法?解引用访问剩余成员是否有效?

这个操作是合法的,解引用访问first成员也是完全有效的:

  1. 指针转换的合法性:
    C标准(C17 §6.3.2.3)允许void*与任意对象类型的指针相互转换。这里把void*类型的vp直接赋值给struct { int first; }*类型的shorn,属于标准明确许可的操作,没有问题。

  2. 解引用访问的有效性:
    这里的核心是严格别名规则和结构体布局规则:

    • shorn指向的地址就是whole的起始地址,也就是whole.first的地址(结构体起始无填充)。当我们通过shorn->first访问时,本质上是在访问whole.first这个int类型的成员。
    • 根据严格别名规则(C17 §6.5),允许通过与对象实际类型兼容的类型访问对象。shorn->first的类型是int,和whole.first的类型完全一致,所以这个访问完全符合规则,不属于未定义行为。
    • 补充一点:如果我们尝试通过shorn访问原结构体中不存在的成员(比如这个匿名结构体如果有第二个成员,去访问它),那就是未定义行为,但在这个例子里只访问第一个成员,是安全合法的。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 16:48:13