简体   繁体   中英

C union - please explain

As far as I understand a union in C can hold only 1 value at a time and I don't really understand how this code in C makes sense since event.window cannot be populated at the same time as event.type ?

while(SDL_PollEvent(&event)) {
switch(event.type)
{
case SDL_WINDOWEVENT:
    switch(event.window.event)

The event is defined as:

typedef union SDL_Event
{
    Uint32 type;                    /**< Event type, shared with all events */
    SDL_CommonEvent common;         /**< Common event data */
    SDL_WindowEvent window;         /**< Window event data */
    SDL_KeyboardEvent key;          /**< Keyboard event data */
    SDL_TextEditingEvent edit;      /**< Text editing event data */
    SDL_TextInputEvent text;        /**< Text input event data */
    SDL_MouseMotionEvent motion;    /**< Mouse motion event data */
    SDL_MouseButtonEvent button;    /**< Mouse button event data */
    SDL_MouseWheelEvent wheel;      /**< Mouse wheel event data */
    SDL_JoyAxisEvent jaxis;         /**< Joystick axis event data */
    SDL_JoyBallEvent jball;         /**< Joystick ball event data */
    SDL_JoyHatEvent jhat;           /**< Joystick hat event data */
    SDL_JoyButtonEvent jbutton;     /**< Joystick button event data */
    SDL_JoyDeviceEvent jdevice;     /**< Joystick device change event data */
    SDL_ControllerAxisEvent caxis;      /**< Game Controller axis event data */
    SDL_ControllerButtonEvent cbutton;  /**< Game Controller button event data */
    SDL_ControllerDeviceEvent cdevice;  /**< Game Controller device event data */
    SDL_QuitEvent quit;             /**< Quit request event data */
    SDL_UserEvent user;             /**< Custom event data */
    SDL_SysWMEvent syswm;           /**< System dependent window event data */
    SDL_TouchFingerEvent tfinger;   /**< Touch finger event data */
    SDL_MultiGestureEvent mgesture; /**< Gesture event data */
    SDL_DollarGestureEvent dgesture; /**< Gesture event data */
    SDL_DropEvent drop;             /**< Drag and drop event data */

    /* This is necessary for ABI compatibility between Visual C++ and GCC
       Visual C++ will respect the push pack pragma and use 52 bytes for
       this structure, and GCC will use the alignment of the largest datatype
       within the union, which is 8 bytes.

       So... we'll add padding to force the size to be 56 bytes for both.
    */
    Uint8 padding[56];
} SDL_Event;

Every aggregate ( struct s probably) member SDL_CommonEvent common; , SDL_WindowEvent window; , SDL_KeyboardEvent key; etc... of the union SDL_Event is starting with some Uint32 field giving the type and that common type field has the same address and size in every union member.

So while indeed a union carries only one field at once in memory (in other words, all union members have the same address), each of them starts with a type and the event.type makes sense; it fetches that type .

Such an idiom is a common way in C to implement tagged unions .

Every member of the SDL_Event union starts with the same two members, Uint32 type and Uint32 timestamp . The C standard specifically says that if a union is currently holding a value of one struct type, but read as another struct type whose first members match the other struct type, it's okay to read those matching members.

All other SDL_X types all begin with a type of 32 bits. In fact, they all seem to include the fields in SDL_CommonEvent at the beginning. This is to facilitate accesing common elements to all sub-structures. Then, by event.common.x you can access all the common elements without having to differentiate the exact type of event.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM