Tuesday, 30 June 2015

MSVC2013, Intellisense and anonymous struct/union bugs

One of the improvements in the C11 standard, is the addition of anonymous structs and unions.  This means that the unnamed element flattens, and all members of the struct or union can be referred to at the same level as the struct or union itself (as long as there are no naming conflicts).

A simplified example use I make of an anonymous struct inside an anonymous union is:

struct my_event_s {
    enum my_event_types event_type_id;
    union {
        struct {
            enum my_key_event_types key_event_type_id;
            union {
            /* Further fields here.. */
            };
        };
        struct {
            enum my_mouse_event_types mouse_event_type_id;
            union {
            /* Further fields here.. */
            };
        };
        struct {
            enum my_touch_event_types touch_event_type_id;
            union {
            /* Further fields here.. */
            };
        };
    };
};
It's a pleasure to program with. But then you reach the stage where you have a different struct, and you want to incorporate a shared anonymous struct (and likely also union) in that. In my case, it was my complete key struct, excerpted from above:
struct {
    enum my_key_event_types key_event_type_id;
    union {
    /* Further fields here.. */
    };
};
One thing you might try, is what I tried. Give the struct a tag, and than just place an anonymous reference to it in the encompassing struct or union.
struct my_key_event_s {
    enum my_key_event_types key_event_type_id;
    union {
    /* Further fields here.. */
    };
};

struct my_event_s {
    enum my_event_types event_type_id;
    union {
        struct my_key_event_s;
        struct {
            enum my_mouse_event_types mouse_event_type_id;
            union {
            /* Further fields here.. */
            };
        };
        struct {
            enum my_touch_event_types touch_event_type_id;
            union {
            /* Further fields here.. */
            };
        };
    };
};
This compiles cleanly, but intellisense will choke on it, and find errors in the code. Intellisense will accept an anonymous struct or union member defined this way within a struct itself. But the moment you try it within a union, then it will choke on not only the struct definitions it accepted up until that point, it will also choke on the union definitions.


It turns out that this is a non-standard (not part of the official C11 standard) feature that Microsoft supports.  It might be argued that usage of it should be avoided, because of this, but with GCC supporting it via the -fms-extensions flag, it is pretty portable.

Personally, I see anonymous structs and unions as a great addition to the C language, that reduce friction without introducing complexity.  And this Microsoft extension should have been a natural part of the standard.  The only downside to it, is that it's actually almost unusable when you're using Microsoft's Visual Studio!  If intellisense chokes on this, then a lot of the value of the editor is undermined, as it's help becomes misleading.

For the record, I'm using Visual Studio 2013, community edition, update 4.  There's a new release of Visual Studio 2015 coming up, which will hopefully mean fixes for this (but who really knows?)  And ideally, a new release of the community edition.