将指向结构的指针转换为其第一个成员

时间:2016-01-22 21:01:47

标签: c

考虑以下示例程序:

#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):   指向适当转换的结构对象的指针指向其初始成员...反之亦然。   在结构对象中可能有未命名的填充,但不在其开头。

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

如果相反第一个成员是指向struct pointed的指针,那该怎么办?我不确定tobase_pointed内的演员阵容。没有铸造垃圾被打印,但没有编译警告/错误。使用强制转换时,会打印base.abase.b的正确值,但如果存在未定义的行为,那么这并不是很有意义。

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

2 个答案:

答案 0 :(得分:2)

代码不只是强制转换,它还取消引用指向struct base的指针。这对于首先获得指向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是适当转换为指向初始成员的指针。你的代码是正确的。

答案 1 :(得分:1)

这个演员是合理的,你需要它,因为你想将指针转换成指针指针。如果你没有演员,取消引用将是不正确的。

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