{"id":38043,"date":"2004-08-26T07:00:00","date_gmt":"2004-08-26T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2004\/08\/26\/why-do-some-structures-end-with-an-array-of-size-1\/"},"modified":"2004-08-26T07:00:00","modified_gmt":"2004-08-26T07:00:00","slug":"why-do-some-structures-end-with-an-array-of-size-1","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20040826-00\/?p=38043","title":{"rendered":"Why do some structures end with an array of size 1?"},"content":{"rendered":"<p><P>\nSome Windows structures are variable-sized,\nbeginning with a fixed header, followed by\na variable-sized array.  When these structures\nare declared,\nthey often declare an array of size 1 where the\nvariable-sized array should be.\nFor example:\n<\/P>\n<PRE>\ntypedef struct _TOKEN_GROUPS {\n    DWORD GroupCount;\n    SID_AND_ATTRIBUTES Groups[ANYSIZE_ARRAY];\n} TOKEN_GROUPS, *PTOKEN_GROUPS;\n<\/PRE>\n<P>\nIf you look in the header files, you&#8217;ll see that ANYSIZE_ARRAY is\n#define&#8217;d to 1, so this declares a structure with a trailing array\nof size one.\n<\/P>\n<P>\nWith this declaration, you would allocate memory for one such\nvariable-sized TOKEN_GROUPS structure like this:\n<\/P>\n<PRE>\nPTOKEN_GROUPS TokenGroups =\n   malloc(FIELD_OFFSET(TOKEN_GROUPS, Groups[NumberOfGroups]));\n<\/PRE>\nand you would initialize the structure like this:\n<PRE>\nTokenGroups-&gt;GroupCount = NumberOfGroups;\nfor (DWORD Index = 0; Index = NumberOfGroups; Index++) {\n  TokenGroups-&gt;Groups[Index] = &#8230;;\n}\n<\/PRE>\n<P>\nMany people think it should have been declared like this:\n<\/P>\n<PRE>\n<I>typedef struct _TOKEN_GROUPS {\n    DWORD GroupCount;\n} TOKEN_GROUPS, *PTOKEN_GROUPS;<\/I>\n<\/PRE>\n<P>\n(In this article, code that is wrong or hypothetical\nwill be italicized.)\n<\/P>\n<P>\nThe code that does the allocation would then go like this:\n<\/P>\n<PRE>\n<I>PTOKEN_GROUPS TokenGroups =\n   malloc(sizeof(TOKEN_GROUPS) +\n          NumberOfGroups * sizeof(SID_AND_ATTRIBUTES));<\/I>\n<\/PRE>\n<P>\nThis alternative has two disadvantages, one cosmetic and one fatal.\n<\/P>\n<P>\nFirst, the cosmetic disadvantage:\nIt makes it harder to access the variable-sized data.\nInitializing the <I>TOKEN_GROUPS<\/I> just allocated would go like this:\n<\/P>\n<PRE>\n<I>TokenGroups-&gt;GroupCount = NumberOfGroups;\nfor (DWORD Index = 0; Index = NumberOfGroups; Index++) {\n  ((SID_AND_ATTRIBUTES *)(TokenGroups + 1))[Index] = &#8230;;\n}<\/I>\n<\/PRE>\n<P>\nThe real disadvantage is fatal.\nThe above code <STRONG>crashes<\/STRONG> on 64-bit Windows.\nThe SID_AND_ATTRIBUTES structure looks like this:\n<\/P>\n<PRE>\ntypedef struct _SID_AND_ATTRIBUTES {\n    PSID Sid;\n    DWORD Attributes;\n    } SID_AND_ATTRIBUTES, * PSID_AND_ATTRIBUTES;\n<\/PRE>\n<P>\nObserve that the first member of this structure is a pointer,\nPSID.  The SID_AND_ATTRIBUTES structure requires pointer alignment,\nwhich on 64-bit Windows is 8-byte alignment.\nOn the other hand, the proposed <I>TOKEN_GROUPS<\/I> structure\nconsists of just a DWORD and therefore requires only 4-byte alignment.\n<I>sizeof(TOKEN_GROUPS)<\/I> is four.\n<\/P>\n<P>\nI hope you see where this is going.\n<\/P>\n<P>\nUnder the proposed structure definition,\nthe array of SID_AND_ATTRIBUTES\nstructures will <STRONG>not<\/STRONG> be placed on an 8-byte\nboundary but only on a 4-byte boundary.\nThe necessary padding between the GroupCount and the first\nSID_AND_ATTRIBUTES is missing.\nThe attempt to access the elements of the array will crash with a\nSTATUS_DATATYPE_MISALIGNMENT exception.\n<\/P>\n<P>\nOkay, you may say, then why not use a zero-length array instead\nof a 1-length array?\n<\/P>\n<P>\nBecause time travel has yet to be perfected.\n<\/P>\n<P>\nZero-length arrays did not become legal Standard C until 1999.\nSince Windows was around long before then, it could not take\nadvantage of that functionality in the C language.\n<\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Some Windows structures are variable-sized, beginning with a fixed header, followed by a variable-sized array. When these structures are declared, they often declare an array of size 1 where the variable-sized array should be. For example: typedef struct _TOKEN_GROUPS { DWORD GroupCount; SID_AND_ATTRIBUTES Groups[ANYSIZE_ARRAY]; } TOKEN_GROUPS, *PTOKEN_GROUPS; If you look in the header files, you&#8217;ll [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-38043","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Some Windows structures are variable-sized, beginning with a fixed header, followed by a variable-sized array. When these structures are declared, they often declare an array of size 1 where the variable-sized array should be. For example: typedef struct _TOKEN_GROUPS { DWORD GroupCount; SID_AND_ATTRIBUTES Groups[ANYSIZE_ARRAY]; } TOKEN_GROUPS, *PTOKEN_GROUPS; If you look in the header files, you&#8217;ll [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/38043","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=38043"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/38043\/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=38043"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=38043"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=38043"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}