What are anonymous structs, and more importantly, how do I tell windows.h to stop using them?

Date:September 7, 2017 / year-entry #202
Tags:code
Orig Link:https://blogs.msdn.microsoft.com/oldnewthing/20170907-00/?p=96956
Comments:    26
Summary:The struct with no name.

Windows header files take advantage of a language extension known as "anonymous structs" or "nameless structs". It looks like this:

typedef struct _devicemode {
  TCHAR dmDeviceName[CCHDEVICENAME];
  WORD dmSpecVersion;
  WORD dmDriverVersion;
  WORD dmSize;
  WORD dmDriverExtra;
  DWORD dmFields;
  union {
    struct {
      short dmOrientation;
      short dmPaperSize;
      short dmPaperLength;
      short dmPaperWidth;
      short dmScale;
      short dmCopies;
      short dmDefaultSource;
      short dmPrintQuality;
    }; // <--- mystery #1
    struct {
      POINTL dmPosition;
      DWORD dmDisplayOrientation;
      DWORD dmDisplayFixedOutput;
    }; // <--- mystery #2
  }; // <--- mystery #3
  short dmColor;
  short dmDuplex;
  short dmYResolution;
  short dmTTOption;
  short dmCollate;
  TCHAR dmFormName[CCHFORMNAME];
  WORD dmLogPixels;
  DWORD dmBitsPerPel;
  DWORD dmPelsWidth;
  DWORD dmPelsHeight;
  union {
    DWORD dmDisplayFlags;
    DWORD dmNup;
  }; // <--- mystery #4
  DWORD dmDisplayFrequency;
#if(WINVER >= 0x0400) 
  DWORD dmICMMethod;
  DWORD dmICMIntent;
  DWORD dmMediaType;
  DWORD dmDitherType;
  DWORD dmReserved1;
  DWORD dmReserved2;
#if (WINVER >= 0x0500) || (_WIN32_WINNT >= 0x0400)
  DWORD dmPanningWidth;
  DWORD dmPanningHeight;
#endif
#endif
} DEVMODE, *PDEVMODE, *LPDEVMODE;

Members of structures and unions normally have names. But in the DEVMODE structure, there are some members with no name. There's a union of two structures, and there's no name for the union (mystery #3); furthermore, the two structures that are members of the union also have no names (mysteries #1 and #2). And there's another union (mystery #4) that has no name.

Let's start with a smaller example. Consider this structure:

struct simple
{
 int a;
 union {
  int b;
  int c;
 } d;
} x;

In this example, we have a structure called simple and an instance of that structure in a variable called x. It consists of the following:

  • An integer a, called x.a.
  • An integer b, called x.d.b, which shares storage with
  • An integer c, called x.d.c.

A nameless union omits the name d.

struct simple2
{
 int a;
 union {
  int b;
  int c;
 }; // <-- no name!
} x2;

This time, the contents are

  • An integer a, called x2.a.
  • An integer b, called x2.b, which shares storage with
  • An integer c, called x2.c.

See what happened there? Omitting the name on the union means that the members of the union are accessible without having to say the name of the union (which is a good thing, because that union has no name).

Nameless unions are available in C and C++,¹ and that's what is happening in the DEVMODE structure. That solves mysteries #3 and #4.

These extensions are supported by both the Visual Studio compiler as well as the GCC compiler. But what if your compiler doesn't?

The answer lies in the actual definition in the header file.

typedef struct _devicemodeW { 
  WCHAR   dmDeviceName[CCHDEVICENAME]; 
  WORD   dmSpecVersion; 
  WORD   dmDriverVersion; 
  WORD   dmSize; 
  WORD   dmDriverExtra; 
  DWORD  dmFields; 
  union {
    struct {
      short dmOrientation;
      short dmPaperSize;
      short dmPaperLength;
      short dmPaperWidth;
      short dmScale; 
      short dmCopies; 
      short dmDefaultSource; 
      short dmPrintQuality; 
    } DUMMYSTRUCTNAME; // magic #1
    struct {
      POINTL dmPosition;
      DWORD  dmDisplayOrientation;
      DWORD  dmDisplayFixedOutput;
    } DUMMYSTRUCTNAME2; // magic #2
  } DUMMYUNIONNAME; // magic #3
  short  dmColor; 
  short  dmDuplex; 
  short  dmYResolution; 
  short  dmTTOption; 
  short  dmCollate; 
  WCHAR  dmFormName[CCHFORMNAME]; 
  WORD   dmLogPixels; 
  DWORD  dmBitsPerPel; 
  DWORD  dmPelsWidth; 
  DWORD  dmPelsHeight; 
  union {
    DWORD  dmDisplayFlags; 
    DWORD  dmNup;
  } DUMMYUNIONNAME2; // magic #4
  DWORD  dmDisplayFrequency; 
#if(WINVER >= 0x0400) 
  DWORD  dmICMMethod;
  DWORD  dmICMIntent;
  DWORD  dmMediaType;
  DWORD  dmDitherType;
  DWORD  dmReserved1;
  DWORD  dmReserved2;
#if (WINVER >= 0x0500) || (_WIN32_WINNT >= 0x0400)
  DWORD  dmPanningWidth;
  DWORD  dmPanningHeight;
#endif
#endif
} DEVMODEW,*LPDEVMODEW,*PDEVMODEW;

There are magic symbols called DUMMYSOMETHINGNAME where a name would normally go.

How curious.

If you then search the Windows header files for definitions of these magic symbols, you find them here in winnt.h:

//
// For compilers that don't support nameless unions/structs
//
#ifndef DUMMYUNIONNAME
#if defined(NONAMELESSUNION) || !defined(_MSC_EXTENSIONS)
#define DUMMYUNIONNAME   u
#define DUMMYUNIONNAME2  u2
#define DUMMYUNIONNAME3  u3
#define DUMMYUNIONNAME4  u4
#define DUMMYUNIONNAME5  u5
#define DUMMYUNIONNAME6  u6
#define DUMMYUNIONNAME7  u7
#define DUMMYUNIONNAME8  u8
#define DUMMYUNIONNAME9  u9
#else
#define DUMMYUNIONNAME
#define DUMMYUNIONNAME2
#define DUMMYUNIONNAME3
#define DUMMYUNIONNAME4
#define DUMMYUNIONNAME5
#define DUMMYUNIONNAME6
#define DUMMYUNIONNAME7
#define DUMMYUNIONNAME8
#define DUMMYUNIONNAME9
#endif
#endif // DUMMYUNIONNAME

#ifndef DUMMYSTRUCTNAME
#if defined(NONAMELESSUNION) || !defined(_MSC_EXTENSIONS)
#define DUMMYSTRUCTNAME  s
#define DUMMYSTRUCTNAME2 s2
#define DUMMYSTRUCTNAME3 s3
#define DUMMYSTRUCTNAME4 s4
#define DUMMYSTRUCTNAME5 s5
#else
#define DUMMYSTRUCTNAME
#define DUMMYSTRUCTNAME2
#define DUMMYSTRUCTNAME3
#define DUMMYSTRUCTNAME4
#define DUMMYSTRUCTNAME5
#endif
#endif // DUMMYSTRUCTNAME

Ah, now the pieces all fall into place.

If you define the symbol NONAMELESSUNION, then the symbols DUMMYSOMETHINGNAME are defined to expand to actual names. For dummy unions, they are u, u2, u3, and so on. For dummy structures, they follow the same pattern, but with s instead of u.

This means that if you indicate that you don't want the header files to use nameless unions, the nameless structures and unions magically get names! The names are not particularly exciting, but at least they have names.

DEVICEMODE dm;
dm.dmPosition = ...;      // if nameless unions are enabled
dm.u.s2.dmPosition = ...; // if nameless unions are disabled

Notice that I didn't use any Microsoft insider information to solve this mystery. All the information you need is right there, if you just follow the symbol definitions.

¹ The history here is unclear. Wikipedia claims that anonymous unions are in C++ and C11, but Stack Overflow claims that C++ supports anonymous unions only because C did. So there's some sort of circular causality loop here.


Comments (26)
  1. laonianren says:

    I was a little surprised I’d never noticed these dummy names. It turns out they are a recent addition. They are in the Windows 10 SDKs, but not the Windows 8 versions.

    1. The common controls ones have been there since 1995.

      1. laonianren says:

        I see. This is a recent addition to DEVMODE, not a recent innovation.

        To explain my confusion: in the past I’ve extracted type information from the Windows headers and anonymous structs were the kind of detail that caused difficulties, so I was surprised I was unaware of a workaround. But it wasn’t a useful workaround because even as recently as Windows 8 it wasn’t used everywhere it was needed.

        Anyway, it’s nice to see compatibility with other compilers improving.

    2. Stefan Kanthak says:

      No, these were not added recently: you can find them in SDKs published in the last Millennium!
      WINNT.H has them at least since the SDK for Windows 7 and .NET 4.

    3. Mark Jansen says:

      See the VARIANT types for examples that are way older.
      There are also macro’s to access the members, that will work both with and without NONAMELESSUNION defined (like V_VT to access the ‘vt’ field.

  2. pc says:

    This makes me curious about how many compilers and compiler options Microsoft tests their SDK/API with. It seems like it’d be a daunting task with a substantial testing matrix.

    1. skSdnW says:

      The MinGW/GCC toolchain use their own set of Win32 header files because of stuff like __uuidof and other non-standard things. I don’t remember if MinGW was ever able to use the official SDK. Maybe a 20 year old SDK would work, who knows.

      I always wondered why the SDK does not do something like #ifndef _MSC_VER #include #endif, then GCC could just ship that file with the correct defines mapping to their __attribute__((whatever)) stuff.

      1. Joshua says:

        Tell me, what do you expect to happen if the standard windows headers were shipped with and used to compile Wine?

        1. skSdnW says:

          I never said anything about Wine, I’m talking about using the official headers with GCC/CLang/whatever to build normal applications. For Wine it is a legal issue, not a technical issue.

          1. Joshua says:

            I went back and checked; mingw branched from cygwin, which quite possibly couldn’t use the official headers, and was used by wine about as soon as it could be.

        2. smf says:

          Shipping the include files and using the include files are two different things. At one point one of the compilers shipped their own, but gave instructions on how to use the official include files if you legally obtained them.

          Microsoft also ship clang with visual studio these days.

    2. Wouldn’t be a easily parallelizable automated solution, though? Seems like something you could manage via CI. The initial configuration for the tests might be complex, but it’s all software; you’re not really relying on user interaction or anything like that. And the answer is a simple binary of whether it compiles or not, with some optional post-functional testing perhaps.

      1. pc says:

        Oh, I’m sure a lot of it is automated. Still a lot of testing. And I assume they would need a lot of those post-compile functional checks to ensure that each and every API is being called with the right calling convention, all these various structs are laid out in memory exactly right, and so forth. There’s a lot of details and nuances that I could imagine being different.

  3. Stefan Kanthak says:

    Notice that I didn’t use any Microsoft insider information to solve this mystery. All the information you need is right there, if you just follow the symbol definitions.
    But also notice that the symbol NONAMELESSUNION and its use/purpose is NOT documented on MSDN’s Using the Windows Headers page, https://msdn.microsoft.com/en-us/library/windows/desktop/aa383745.aspx, where every developer and his dog would expect them.

    1. Right. I’m saying that if you see them in the header file, you can chase down the definitions and figure out what they’re for based on their names.

      1. Stefan Kanthak says:

        Is your recommendation also applicable to (elsewhere not documented) structure definitions like RTL_VERIFIER_PROVIDER_DESCRIPTOR etc., or function prototype like RtlSetHeapInformation, RtlQueryHeapInformation etc. found in winnt.h?

        1. Turning off nameless unions has no binary effect. The structure has the same layout either way. The only difference is how you refer to its members in source code. The resulting binary is identical. Calling undocumented functions or passing an undocumented structure affects the resulting binary. I can’t believe I have to explain this.

    2. ErikF says:

      Stuff like this should be something that only the implementor should have to worry about IMO: Note that the page that you referenced discusses how the headers work with VC++. If your compiler ships with Windows headers and can produce PE files correctly, then it should be the responsibility of the compiler vendor to sort this out and document any requirements; otherwise you’re using the headers in an unsupported way and have to deal with any issues yourself.

      1. Stefan Kanthak says:

        Setting NONAMELESSUNION but forces the programmer to change the sources which reference such previously unnamed unions.
        JFTR: the MSDN article talks about the Windows headers in general; Visual C++ is a subsection of it.

  4. JM says:

    I remember asking in comp.lang.c why anonymous unions weren’t supported in ISO C, given their obvious usefulness. That was during the days of C99. Didn’t know they’ve since been added. Nor do I recall what answers I got (I seem to recall they were along the lines of “it’s not *that* useful a feature”).

  5. Alan says:

    What compilers are people using that don’t support anonymous structs and unions?

    1. SimonRev says:

      I have to trust my memory of an experience more than a decade ago, but IIRC, having used Visual C++ for many years, I assumed anonymous structs were part of the C++ language and was surprised to find out that while anonymous unions were part of the language, anonymous structs were not. I think I had to write a quick Linux program and found that GCC was either generating warnings or errors at my usage of them.

      1. Matteo Italia says:

        They were warnings for sure, and probably only with -pedantic; I used anonymous unions with gcc many times, they are a quite widespread extension (and a very convenient one for sure).

    2. Joshua Schaeffer says:

      The C# compiler doesn’t support anonymous unions. Preserving exact parity between interop definitions and Win32 header files is harder without tricks like DUMMYUNIONNAME.

  6. Myria says:

    I want to try to get the C++ committee to approve anonymous structs. Most compilers already allow anonymous structs, though may warn about them being an extension. They’re clearly useful in certain context.

  7. s says:

    Gah! Nameless structs are a curse_ed evil from a primative time and should forever be banished from civilized society. It is the evil so great that one dares not speak its name (it has no name). Just say no.

Comments are closed.


*DISCLAIMER: I DO NOT OWN THIS CONTENT. If you are the owner and would like it removed, please contact me. The content herein is an archived reproduction of entries from Raymond Chen's "Old New Thing" Blog (most recent link is here). It may have slight formatting modifications for consistency and to improve readability.

WHY DID I DUPLICATE THIS CONTENT HERE? Let me first say this site has never had anything to sell and has never shown ads of any kind. I have nothing monetarily to gain by duplicating content here. Because I had made my own local copy of this content throughout the years, for ease of using tools like grep, I decided to put it online after I discovered some of the original content previously and publicly available, had disappeared approximately early to mid 2019. At the same time, I present the content in an easily accessible theme-agnostic way.

The information provided by Raymond's blog is, for all practical purposes, more authoritative on Windows Development than Microsoft's own MSDN documentation and should be considered supplemental reading to that documentation. The wealth of missing details provided by this blog that Microsoft could not or did not document about Windows over the years is vital enough, many would agree an online "backup" of these details is a necessary endeavor. Specifics include:

<-- Back to Old New Thing Archive Index