Search code examples
cpointersxcb

Why is typecasting between to different structure pointers feasible?


This code snippet is copied from the last tutorial example of the 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, pointer to xcb_generic_event_t is typecasted to pointer to xcb_expose_event_t, is it a good way to do such an operation in standard C language? And please explain what is the meaning of it?


Solution

  • It's feasible because both structures start with the same few members.

    I haven't used xcb, but just looking at the code using it I presume that xcb_wait_for_event(), which returns a pointer to an xcb_generic_event_t object, in this case returns a pointer that actually points to an xcb_expose_event_t event. The former is, as the name implies, a "generic" type that can be used as a placeholder for any of several more specific types. The first few members (including the response_type member) are shared, in the sense that they have the same size and are stored at the same offset in both structure types. Thus the code can safely refer to the response_type member of an xcb_generic_event_t object, and based on that infer that the object is really an xcb_expose_event_t object. The pointer cast allows the code to reinterpret the object as an xcb_expose_event_t object.

    Looking at the linked definitions of the two types, I see that xcb_generic_event_t actually has 5 members, and only the first 3 are shared with xcb_expose_event_t. This is unlikely to cause problems as long as the code doesn't refer to the final 2 members of the xcb_generic_event_t.

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

    One special guarantee is made in order to simplify the use of unions: if a union contains several structures that share a common initial sequence (see below), and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them anywhere that a declaration of the completed type of the union is visible. Two structures share a common initial sequence if corresponding members have compatible types (and, for bit-fields, the same widths) for a sequence of one or more initial members.

    Strictly speaking, this applies only when the two structures are members of a union. But the easiest way for a C compiler to satisfy this guarantee is to give all structures with a common initial subsequence the same layout for that subsequence. The behavior if the code in the question might not be 100% well defined, but in practice it's reasonably certain to be safe. (It's conceivable that an aggressive optimizing compiler might perform some transformation that causes the code to misbehave, but such an optimization would break a lot of existing code, something compiler implementers are highly motivated to avoid.)