【问题标题】:Converting a pointer to a struct to its first member将指向结构的指针转换为其第一个成员
【发布时间】:2016-04-29 14:17:32
【问题描述】:

考虑以下示例程序:

#include <stdio.h>

struct base {
    int a, b;
};

struct embedded {
    struct base base;
    int c, d;
};

struct pointed {
    struct base* base;
    int c, d;
};

static void base_print(struct base* x) {
    printf("a: %d, b: %d\n", x->a, x->b);
}

static void tobase_embedded(void* object) {
    base_print(object); // no cast needed, suitably converted into first member.
}

static void tobase_pointed(void* object) {
    struct base* x = *(struct base**) object; // need this cast?
    base_print(x);
}

int main(void) {
    struct embedded em = {{4, 2}};
    struct pointed pt = {&em.base};
    tobase_embedded(&em);
    tobase_pointed(&pt);
    return 0;
}

编译:

$ gcc -std=c99 -O2 -Wall -Werror -pedantic -o main main.c

预期的输出是:

$ ./main
a: 4, b: 2
a: 4, b: 2

C99 标准是这样描述结构的第一个成员的:

C99 6.7.2.1 (13): 一个指向结构对象的指针,经过适当的转换,指向它的初始成员......反之亦然。 as 结构对象中可能有未命名的填充,但不是在其开头。

在示例程序中,指向struct embedded 的指针被转换为指向struct base 的指针(通过void*),无需显式转换。

如果第一个成员是struct pointed 中的指向基址的指针怎么办?我不确定tobase_pointed 中的演员阵容。不打印强制转换垃圾,但没有编译警告/错误。通过强制转换,base.abase.b 的正确值会被打印出来,但如果存在未定义的行为,这并不意味着太多。

struct pointed 转换为其第一个成员struct base* 的演员是否正确?

【问题讨论】:

  • struct pointed 的第一个成员是指向struct base 的指针。这将需要取消引用 void *object。但是你不能在不告诉编译器如何取消引用指针的情况下取消引用void *,因此需要强制转换。

标签: c


【解决方案1】:

这种转换是合理的,您需要它是因为您想将指针转换为指向指针的指针。如果不强制转换,取消引用将不正确。

换句话说,您的base*pt 对象具有相同的地址。因此,您可以通过指向 pt 的指针来访问它。但是你必须取消引用它。

【讨论】:

    【解决方案2】:

    代码不只是强制转换,它还取消引用指向 struct base 的指针。这是首先获得指向基址的指针所必需的。

    如果函数 tobase_pointed 被删除,这就是您的代码中发生的情况:

    struct pointed pt = {&em.base};
    void* object = &pt;                  //pass to the function
    struct base** bs = object;           //the cast in the function
    assert( bs == (struct base**)&pt ) ; //bs points to the struct pointed
    assert( bs == &(pt.base) ) ;         //bs also points to the initial member struct base* base
    struct base* b = *bs ;               //the dereference in the function
    base_print(x);
    

    bs 是被适当转换为指向初始成员的指针。你的代码是正确的。

    【讨论】:

    • 一步一步看就明白了,谢谢。
    猜你喜欢
    • 2015-03-11
    • 2015-01-24
    • 1970-01-01
    • 2011-11-10
    • 2023-03-12
    • 1970-01-01
    • 2013-09-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多