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

C 为什么在不同结构指针之间进行类型转换是可行的?,c,pointers,xcb,C,Pointers,Xcb,此代码段复制自: 在第5行中,指针指向被类型化为指针指向,这是用标准C语言进行此类操作的好方法吗?请解释一下它是什么意思?来自C编程语言第二版 A.8.3结构和联合声明 如果指向结构的指针被强制转换为指向其 第一个成员,结果引用第一个成员 但是在这种情况下,xcb\u expose\u event\u t被定义为 typedef struct { uint8_t response_type; /* The type of the event, here it is XCB_EX

此代码段复制自:

在第5行中,指针指向被类型化为指针指向,这是用标准C语言进行此类操作的好方法吗?请解释一下它是什么意思?

来自C编程语言第二版

A.8.3结构和联合声明

如果指向结构的指针被强制转换为指向其 第一个成员,结果引用第一个成员

但是在这种情况下,
xcb\u expose\u event\u t
被定义为

typedef struct {
    uint8_t      response_type; /* The type of the event, here it is XCB_EXPOSE */
    uint8_t      pad0;
    uint16_t     sequence;
    xcb_window_t window;        /* The Id of the window that receives the event (in case */
                                /* our application registered for events on several windows */
    uint16_t     x;             /* The x coordinate of the top-left part of the window that needs to be redrawn */
    uint16_t     y;             /* The y coordinate of the top-left part of the window that needs to be redrawn */
    uint16_t     width;         /* The width of the part of the window that needs to be redrawn */
    uint16_t     height;        /* The height of the part of the window that needs to be redrawn */
    uint16_t     count;
} xcb_expose_event_t;
如您所见,
struct
的第一个成员未定义为
xcb\u generic\u event\u t
,在我看来,这似乎是未定义的行为。

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

我没有使用过xcb,但只要看看使用它的代码,我就假定
xcb\u wait\u for\u event()
,它返回一个指向
xcb\u generic\u event\u t
对象的指针,在这种情况下,返回一个实际指向
xcb\u expose\u event\u
事件的指针。顾名思义,前者是一种“泛型”类型,可以用作几种更具体类型中任何一种的占位符。前几个成员(包括
response\u type
成员)是共享的,因为它们具有相同的大小,并且在两种结构类型中存储在相同的偏移量。因此,代码可以安全地引用
xcb\u generic\u event\t
对象的
response\u type
成员,并据此推断该对象实际上是
xcb\u expose\u event\t
对象。指针强制转换允许代码将对象重新解释为
xcb\u expose\u event\t
对象

查看这两种类型的链接定义,我发现
xcb\u generic\u event\u t
实际上有5个成员,只有前3个成员与
xcb\u expose\u event\u t
共享。只要代码没有引用
xcb\u generic\u事件的最后两个成员,这就不太可能导致问题

C标准对这种情况做出了特殊保证。引用6.5.3.2第6段:

为简化工会的使用,提供了一项特殊保证: 如果一个并集包含多个共享公共首字母的结构 序列(请参见下文),以及union对象当前是否包含一个 在这些结构中,允许检查公共初始值 它们中任何一个的一部分,即完成类型的声明 联盟的未来是显而易见的。两个结构共享一个共同的首字母 如果相应的成员具有兼容的类型(和,对于 一个或多个初始值序列的位字段(相同宽度) 成员们


严格地说,这只适用于两个机构是工会成员的情况。但是,对于C编译器来说,满足这一保证的最简单方法是为具有公共初始子序列的所有结构提供该子序列的相同布局。问题中的代码的行为可能没有100%定义良好,但在实践中,它是安全的。(可以想象,一个激进的优化编译器可能会执行一些导致代码行为异常的转换,但这样的优化会破坏很多现有代码,编译器实现人员非常希望避免这种情况。)

是的,UB是我在这个XCB结构定义中所关心的。
typedef struct {
    uint8_t      response_type; /* The type of the event, here it is XCB_EXPOSE */
    uint8_t      pad0;
    uint16_t     sequence;
    xcb_window_t window;        /* The Id of the window that receives the event (in case */
                                /* our application registered for events on several windows */
    uint16_t     x;             /* The x coordinate of the top-left part of the window that needs to be redrawn */
    uint16_t     y;             /* The y coordinate of the top-left part of the window that needs to be redrawn */
    uint16_t     width;         /* The width of the part of the window that needs to be redrawn */
    uint16_t     height;        /* The height of the part of the window that needs to be redrawn */
    uint16_t     count;
} xcb_expose_event_t;