{"id":22973,"date":"2008-03-27T10:00:00","date_gmt":"2008-03-27T10:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2008\/03\/27\/why-do-structures-get-tag-names-even-if-there-is-a-typedef\/"},"modified":"2008-03-27T10:00:00","modified_gmt":"2008-03-27T10:00:00","slug":"why-do-structures-get-tag-names-even-if-there-is-a-typedef","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20080327-00\/?p=22973","title":{"rendered":"Why do structures get tag names even if there is a typedef?"},"content":{"rendered":"<p>\nAs we noted last time, structure tags are different from the\ntypedef name as a historical artifact of earlier versions of the C\nlanguage.\nBut what about just leaving out the name entirely?\n<\/p>\n<pre>\ntypedef struct {\n ...\n} XYZ;\n<\/pre>\n<p>\nOne problem with this approach is that it becomes impossible to make\na forward reference to this structure because it has no name.\nFor example, if you wanted to write a prototype for a function\nthat took one of these structures,\nand you could not be sure that the header file defining the <code>XYZ<\/code>\ntype definition has already been included, you can still refer to\nthe structure by its tag name.\n<\/p>\n<pre>\n\/\/ in header file A\ntypedef struct tagXYZ {\n ...\n} XYZ;\n\/\/ in header file B\nBOOL InitializeFromXYZ(const struct tagXYZ *pxyz);\n<\/pre>\n<p>\nThe two header files can be included in either order\nbecause header file&nbsp;B uses a forward reference to the\n<code>XYZ<\/code> structure.\nNaturally, you would hope that people would include header file&nbsp;A\nbefore header file&nbsp;B, but there can be cases where it is not\npractical.\n(For example, header file&nbsp;A may contain definitions that conflict\nwith something else that the program needs,\nor header file&nbsp;A may change its behavior based on what has\nalready been <code>#define<\/code>&#8216;d, and you don&#8217;t want to\ninclude it before the application has a chance to set up those\n<code>#define<\/code>s.)\n<\/p>\n<p>\nBut a more important reason to avoid anonymous types is that\nit creates problems for MIDL.\n<\/p>\n<p>\nOkay, it doesn&#8217;t actually create problems for MIDL.\nMIDL handles it just fine, but the way MIDL handles it\n<i>creates problems for you<\/i>,\nfor when you create an anonymous type in MIDL,\nsuch as an anonymous structure above, or an anonymous enumeration\nlike this:\n<\/p>\n<pre>\ntypedef enum { ... } XYZ;\n<\/pre>\n<p>\nMIDL <i>auto-generates a name for you<\/i>.\nFor example, the above enumeration might end up in the\ngenerated header file as\n<\/p>\n<pre>\ntypedef enum <font COLOR=\"blue\">__MIDL___MIDL_itf_scratch_0000_0001<\/font>\n{\n    ...\n} XYZ;\n<\/pre>\n<p>\nThe kicker is that the auto-generated name changes if you\nchange the IDL file.\nAnd since typedefs are just shorthand for the underlying type\n(rather than a type in and of themselves),\nthe name saved in the PDB is the unwieldy\n<code>__MIDL___MIDL_itf_scratch_0000_0001<\/code>.\nTry typing that into the debugger, yuck.\n<\/p>\n<p>\nFurthermore, having the name change from build to build means\nthat you have to make sure code libraries are all built from\nexactly the same header file versions,\neven if the changes are ostensibly compatible.\nFor example, suppose you compile a library with a particular\nversion of the header file, and then you add a structure to the\nMIDL file which has no effect on the functions and structures\nthat the library used.\nBut still, since you changed the MIDL file, this changes\nthe auto-generated symbol names.\nNow you compile a program with the new header file and link\nagainst the library.\nResult: A whole bunch of errors,\nbecause the library, say, exports a function that expects\nits first parameter to be a\n<code>__MIDL___MIDL_itf_scratch_0000_0001<\/code>\n(because the library was built from the older MIDL-generated header file),\nbut your program imports a function that expects its first\nparameter to be a\n<code>__MIDL___MIDL_itf_scratch_0001_0002<\/code>\n(because you compiled with the newer MIDL-generated header file).\n<\/p>\n<p>\nWhat&#8217;s more, when you update the header file, your source control\nsystem will recognize hundreds of changes, since the MIDL\ncompiler generated a whole different set of names\nwhich no longer match the names from the previous version of\nthe header file, even though you didn&#8217;t change the structure!\nThis isn&#8217;t fatal, but it makes digging through source code\nhistory more of an ordeal since the &#8220;real changes&#8221; are buried\namidst hundreds of lines of meaningless changes.\n<\/p>\n<p>\nNow, this particular rule of thumb is not universally\nadhered-to in Windows header files,\nin large part, I believe, simple because people aren&#8217;t aware\nof the potential for mischief.\nBut maybe now that I wrote them up,\npeople might start paying closer attention.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>As we noted last time, structure tags are different from the typedef name as a historical artifact of earlier versions of the C language. But what about just leaving out the name entirely? typedef struct { &#8230; } XYZ; One problem with this approach is that it becomes impossible to make a forward reference to [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[2],"class_list":["post-22973","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-history"],"acf":[],"blog_post_summary":"<p>As we noted last time, structure tags are different from the typedef name as a historical artifact of earlier versions of the C language. But what about just leaving out the name entirely? typedef struct { &#8230; } XYZ; One problem with this approach is that it becomes impossible to make a forward reference to [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/22973","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=22973"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/22973\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=22973"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=22973"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=22973"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}