为什么不同结构指针之间的类型转换是可行的?

Kev*_*ong 3 c pointers xcb

此代码段是从XCB中事件上一个教程示例中复制而来的:

01    xcb_generic_event_t *event;
02    while ( (event = xcb_wait_for_event (connection)) ) {
03        switch (event->response_type & ~0x80) {
04        case XCB_EXPOSE: {
05            xcb_expose_event_t *expose = (xcb_expose_event_t *)event;
06            printf ("Window %"PRIu32" exposed. Region to be redrawn at location (%"PRIu16",%"PRIu16"), with dimension (%"PRIu16",%"PRIu16")\n",
07                    expose->window, expose->x, expose->y, expose->width, expose->height );
08            break;
09        }
Run Code Online (Sandbox Code Playgroud)

在第5行,指向指向的xcb_generic_event_t指针xcb_expose_event_t,是否是在标准C语言中执行此类操作的好方法?请解释一下它的含义是什么?

Kei*_*son 5

这是可行的,因为两个结构都以相同的几个成员开始.

我没有使用过xcb,但只是查看使用它的代码我假设xcb_wait_for_event()它返回一个指向xcb_generic_event_t对象的指针,在这种情况下返回一个实际指向一个xcb_expose_event_t事件的指针.顾名思义,前者是一种"通用"类型,可用作几种更具体类型的占位符.前几个成员(包括response_type成员)是共享的,因为它们具有相同的大小并且在两种结构类型中存储在相同的偏移处.因此,代码可以安全地引用对象的response_type成员xcb_generic_event_t,并基于该推断该对象实际上是xcb_expose_event_t对象.指针转换允许代码将对象重新解释为xcb_expose_event_t对象.

查看两种类型的链接定义,我看到xcb_generic_event_t实际上有5个成员,只有前3个与之共享xcb_expose_event_t.只要代码没有引用最终的2个成员,这就不太可能引起问题xcb_generic_event_t.

并且C标准作出了特殊保证,涵盖了这种情况.引用N1570 6.5.3.2,第6段:

为了简化联合的使用,我们做了一个特殊的保证:如果一个联合包含几个共享一个共同初始序列的结构(见下文),并且如果联合对象当前包含这些结构中的一个,则允许检查公共其中任何一个的初始部分都可以看到完整类型的联合声明.如果对应的成员具有一个或多个初始成员的序列的兼容类型(并且对于位字段,具有相同的宽度),则两个结构共享共同的初始序列.

严格地说,这仅适用于两个结构是联合的成员.但是,C编译器满足此保证的最简单方法是为所有具有共同初始子序列的结构提供与该子序列相同的布局.如果问题中的代码可能没有100%明确定义的行为,但实际上它确实是安全的.(可以想象,一个积极的优化编译器可能会执行一些导致代码行为不当的转换,但是这样的优化会破坏很多现有代码,编译器实现者会非常积极地避免这种情况.)