Why is casting between different structure pointers possible?

This code snippet is copied from the last example of training events in 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        }

      

In the 5th line, the pointer to is xcb_generic_event_t

assigned to the pointer to xcb_expose_event_t

, is this a good way to do such an operation in the standard C language? And please explain what this means?

+3


source to share


2 answers


This is possible because both structures start with the same few members.

I haven't used xcb, but just looking at the code using it. I suppose that xcb_wait_for_event()

which returns a pointer to an object xcb_generic_event_t

, in this case, returns a pointer that actually points to the xcb_expose_event_t

event. The first, as the name suggests, means a "generic" type that can be used as a placeholder for any of several more specific types. The first few members (including the member response_type

) are common in the sense that they are the same size and are stored at the same offset in both types of structure. This way, code can safely refer to an element of an response_type

object xcb_generic_event_t

and infer from this that the object is indeed an object xcb_expose_event_t

. Pointer assignment allows code to reinterpret an object as an objectxcb_expose_event_t

...

Looking at the related definitions of the two types, I can see that xcb_generic_event_t

it actually has 5 members and only the first 3 are shared with xcb_expose_event_t

. This is unlikely to cause problems unless the code is in the last 2 members xcb_generic_event_t

.



And the C standard makes a special guarantee that covers this case. Quoting N1570 6.5.3.2 paragraph 6:

: , (. ), , , . , (, -, ) .

Strictly speaking, this only applies when the two structures are members of the union. But the simplest way for the C compiler to fulfill this guarantee is to provide all structs with a common starting subsequence the same layout for that subsequence. Behavior if the code in the question may not be 100% well-defined, but in practice it is reasonably well-defined to be safe. (One might assume that an aggressive optimizing compiler might perform some transformation that would make the code misbehave, but such an optimization would break a lot of existing code, for which the compiler designers are highly motivated to avoid this.)

+5


source


From the C Programming Language - Second Edition

A.8.3 Union structure and declarations

If a pointer to a structure is passed to the type of a pointer to its first member, the result refers to the first member.



But in this case it is xcb_expose_event_t

defined as

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;

      

As you can see the first element struct

is undefined as xcb_generic_event_t

seems to me to be undefined.

+2


source







All Articles