[英]Why is typecasting between to different structure pointers feasible?
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 }
在第5行中,指向xcb_generic_event_t
指針被xcb_generic_event_t
為指向xcb_expose_event_t
指針,這是在標准C語言中執行此類操作的好方法嗎? 請解釋一下它的含義是什么?
這是可行的,因為兩個結構都以相同的幾個成員開始。
我沒有使用過xcb,但只是看一下使用它的代碼我假設xcb_wait_for_event()
返回一個指向xcb_generic_event_t
對象的指針,在這種情況下返回一個實際指向xcb_expose_event_t
事件的指針。 顧名思義,前者是一種“通用”類型,可用作幾種更具體類型的占位符。 前幾個成員(包括response_type
成員)是共享的,因為它們具有相同的大小並且在兩種結構類型中存儲在相同的偏移量中。 因此,代碼可以安全地引用xcb_generic_event_t
對象的response_type
成員,並基於該推斷該對象實際上是xcb_expose_event_t
對象。 指針轉換允許代碼將對象重新解釋為xcb_expose_event_t
對象。
查看兩種類型的鏈接定義,我看到xcb_generic_event_t
實際上有5個成員,只有前3個與xcb_expose_event_t
共享。 只要代碼不引用xcb_generic_event_t
的最后2個成員,這就不太可能導致問題。
C標准作為特殊保證涵蓋了這種情況。 引用N1570 6.5.3.2,第6段:
為了簡化聯合的使用,我們做了一個特殊的保證:如果一個聯合包含幾個共享一個共同初始序列的結構(見下文),並且如果聯合對象當前包含這些結構中的一個,則允許檢查公共其中任何一個的初始部分都可以看到完整類型的聯合聲明。 如果對應的成員具有一個或多個初始成員的序列的兼容類型(並且對於位字段,具有相同的寬度),則兩個結構共享共同的初始序列 。
嚴格地說,這僅適用於兩個結構是聯合的成員。 但是,C編譯器滿足此保證的最簡單方法是為所有具有共同初始子序列的結構提供與該子序列相同的布局。 如果問題中的代碼可能沒有100%明確定義的行為,但實際上它確實是安全的。 (可以想象,一個積極的優化編譯器可能會執行一些導致代碼行為不當的轉換,但是這樣的優化會破壞很多現有代碼,編譯器實現者很有動力避免這種情況。)
來自C編程語言 - 第二版
A.8.3結構和聯盟聲明
如果將指向結構的指針強制轉換為指向其第一個成員的指針類型,則結果將引用第一個成員。
但在這種情況下, xcb_expose_event_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_generic_event_t
,似乎不確定的行為給我。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.