title: Does the C standard consider that there are one or two 'struct uperms_entry' types in this header?
body: <p>Can you give chapter and verse from one of the three C standards (preferably C99 or C11) which indicates whether the following header file has one or two <code>struct uperms_entry</code> types in it?</p>
  
  <pre><code>#ifndef UPERMS_CACHE_INCLUDE
  #define UPERMS_CACHE_INCLUDE
  
  typedef struct mutex MT_MUTEX;
  
  typedef struct uperms_cache
  {
      MT_MUTEX            *cache_lock;
      int                  processing;
      struct uperms_entry *uperms_list;  // No prior struct uperms_entry
  } uperms_cache_t;
  
  typedef struct uperms_entry // Does this define a different struct uperms_entry?
  {
      char                 username[32];
      int                  perms;
      struct uperms_entry *next;
  } uperms_entry_t;
  
  #endif /* UPERMS_CACHE_INCLUDE */
  </code></pre>
  
  <p>Adjunct questions:</p>
  
  <ol>
  <li>If there are two types, is there any way to get GCC to report the issue?</li>
  <li>If there are two types, does it ever matter in practice?</li>
  </ol>
  
  <p>(I think the answers are 'yes — strictly there are two types', and then (1) No and (2) No.)</p>
  
  <p><em>Context: internal code review — I'd like the order of the structures reversed, but I'm not sure whether I'm being completely overly pedantic.</em></p>
  
  <p><strong>Update:</strong></p>
  
  <p>Clearly, the answer to the initial question is 'there is one <code>struct uperms_entry</code>' and therefore the questions numbered 1 and 2 are moot.  I'm glad I checked before throwing a hissy fit in a code review.</p>
  
  <h2>Background thinking</h2>
  
  <p>This section was added long after the primary question was resolved.</p>
  
  <hr>
  
  <p>Here are some extensive but relevant quotes from ISO/IEC 9899:2011:</p>
  
  <blockquote>
    <h3>§6.2.7 Compatible type and composite type</h3>
    
    <p>¶1 Two types have compatible type if their types are the same.
    Additional rules for determining whether two types are compatible are
    described in 6.7.2 for type specifiers, in 6.7.3 for type qualifiers,
    and in 6.7.6 for declarators.<sup>55)</sup> Moreover, two structure,
    union, or enumerated types declared in separate translation units are
    compatible if their tags and members satisfy the following requirements:
    If one is declared with a tag, the other shall be declared with the same
    tag.  If both are completed anywhere within their respective translation
    units, then the following additional requirements apply: there shall be
    a one-to-one correspondence between their members such that each pair of
    corresponding members are declared with compatible types; if one member
    of the pair is declared with an alignment specifier, the other is
    declared with an equivalent alignment specifier; and if one member of
    the pair is declared with a name, the other is declared with the same
    name.  For two structures, corresponding members shall be declared in
    the same order.  For two structures or unions, corresponding bit-fields
    shall have the same widths.  For two enumerations, corresponding members
    shall have the same values.</p>
    
    <p><sup>55)</sup> Two types need not be identical to be compatible.</p>
    
    <h3>§6.7.2.1 Structure and union specifiers</h3>
    
    <p>¶8 The presence of a struct-declaration-list in a
    struct-or-union-specifier declares a new type, within a translation
    unit.  The struct-declaration-list is a sequence of declarations for the
    members of the structure or union.  If the struct-declaration-list does
    not contain any named members, either directly or via an anonymous
    structure or anonymous union, the behavior is undefined.  The type is
    incomplete until immediately after the <code>}</code> that terminates the list, and
    complete thereafter.</p>
    
    <h3>§6.7.2.3 Tags</h3>
    
    <p>¶4 All declarations of structure, union, or enumerated types that have
    the same scope and use the same tag declare the same type.  Irrespective
    of whether there is a tag or what other declarations of the type are in
    the same translation unit, the type is incomplete<sup>129)</sup> until
    immediately after the closing brace of the list defining the content,
    and complete thereafter.</p>
    
    <p>¶5 Two declarations of structure, union, or enumerated types which are
    in different scopes or use different tags declare distinct types.  Each
    declaration of a structure, union, or enumerated type which does not
    include a tag declares a distinct type.</p>
    
    <p>¶6 A type specifier of the form</p>
    
    <p><code>struct-or-union identifier</code><sub>opt</sub> <code>{ struct-declaration-list }</code></p>
    
    <p>or</p>
    
    <p><code>enum identifier</code><sub>opt</sub> <code>{ enumerator-list }</code></p>
    
    <p>or</p>
    
    <p><code>enum identifier</code><sub>opt</sub> <code>{ enumerator-list , }</code></p>
    
    <p>declares a structure, union, or enumerated type.  The list defines the
    structure content, union content, or enumeration content.  If an
    identifier is provided,<sup>130)</sup> the type specifier also declares
    the identifier to be the tag of that type.</p>
    
    <p>¶7 A declaration of the form</p>
  
  <pre><code>struct-or-union identifier ;
  </code></pre>
    
    <p>specifies a structure or union type and declares the identifier as a
    tag of that type.<sup>131)</sup></p>
    
    <p>¶8 If a type specifier of the form</p>
  
  <pre><code>struct-or-union identifier
  </code></pre>
    
    <p>occurs other than as part of one of the above forms, and no other
    declaration of the identifier as a tag is visible, then it declares an
    incomplete structure or union type, and declares the identifier as the
    tag of that type.<sup>131)</sup></p>
    
    <p>¶9 If a type specifier of the form</p>
  
  <pre><code>struct-or-union identifier
  </code></pre>
    
    <p>or</p>
  
  <pre><code>enum identifier
  </code></pre>
    
    <p>occurs other than as part of one of the above forms, and a declaration
    of the identifier as a tag is visible, then it specifies the same type
    as that other declaration, and does not redeclare the tag.</p>
    
    <p>¶12 EXAMPLE 2 To illustrate the use of prior declaration of a tag to
    specify a pair of mutually referential structures, the declarations</p>
  
  <pre><code>struct s1 { struct s2 *s2p; /* ... */ }; // D1
  struct s2 { struct s1 *s1p; /* ... */ }; // D2
  </code></pre>
    
    <p>specify a pair of structures that contain pointers to each other.
    Note, however, that if s2 were already declared as a tag in an
    enclosing scope, the declaration D1 would refer to it, not to the tag
    s2 declared in D2.  To eliminate this context sensitivity, the
    declaration</p>
  
  <pre><code>struct s2;
  </code></pre>
    
    <p>may be inserted ahead of D1.  This declares a new tag s2 in the inner
    scope; the declaration D2 then completes the specification of the new type.</p>
    
    <p><sup>129)</sup> An incomplete type may only by used when the size of
    an object of that type is not needed.  It is not needed, for example,
    when a typedef name is declared to be a specifier for a structure or
    union, or when a pointer to or a function returning a structure or union
    is being declared.  (See incomplete types in 6.2.5.)  The specification
    has to be complete before such a function is called or defined.</p>
    
    <p><sup>130)</sup> If there is no identifier, the type can, within the
    translation unit, only be referred to by the declaration of which it is
    a part.  Of course, when the declaration is of a typedef name,
    subsequent declarations can make use of that typedef name to declare
    objects having the specified structure, union, or enumerated type.</p>
    
    <p><sup>131)</sup> A similar construction with enum does not exist.</p>
    
    <h3>§6.7.3 Type qualifiers</h3>
    
    <p>¶10 For two qualified types to be compatible, both shall have the
    identically qualified version of a compatible type; the order of
    type qualifiers within a list of specifiers or qualifiers does not
    affect the specified type.</p>
  </blockquote>
  
  <p><em>The discussion in §6.7.6 is related to pointer, arrays, and function
  declarators and does not really affect structures or unions.</em></p>
  
  <hr>
  
  <p>I was aware of Example 2 when I wrote the question.  This is some
  thinking out loud about some of what the information above means.</p>
  
  <p>Consider this example, which compiles cleanly:</p>
  
  <pre><code>#include &lt;stdio.h&gt;
  struct r1 { int x; };
  
  struct r1;
  
  struct r1 p0;
  
  //struct r1 { int y; };     // Redefinition of struct r1
  
  extern void z(void);
  
  void z(void)
  {
      struct r1 p1 = { 23 };
      struct r1;
      //struct r1 p2;         // Storage size of p2 is not known
      struct r2 { struct r1 *rn; int y; };
      struct r1 { struct r2 *rn; int z; };
      struct r2 p = { 0, 1 };
      struct r1 q = { &amp;p, 2 };
      p.rn = &amp;q;
      printf("p.y = %d, q.z = %d\n", p.y, q.z);
      printf("p1.x = %d\n", p1.x);
  }
  </code></pre>
  
  <p>The function illustrates when Example 2 applies, but is not sensible
  code.  The declaration of <code>p1</code> in the function is would be a structure
  of the same type as the global variable <code>p0</code>.  Even though its type name
  is <code>struct r1</code>, it is of a different (and incompatible) type from the
  type of the local variable <code>p</code>.</p>
  
  <p>The redefinition of <code>struct r1</code> at the global level is not allowed,
  regardless of whether the element is named <code>x</code> or <code>y</code>.  The prior
  <code>struct r1;</code> is a no-op in this context.</p>
  
  <p>One interesting issue is 'can function <code>z</code> pass <code>p</code> or <code>q</code> to any other
  function (call it <code>a</code>)?  The answer is a qualified 'yes', and some of
  the constraints are interesting.  (It would also be appalling coding
  style to try it, verging on the insane.)  The function must exist in a
  separate translation unit (TU).  The function declaration must be inside
  function <code>z</code> (because if it is outside the function, its prototype must
  refer to the <code>struct r1</code> defined outside the function, not the <code>struct
  r1</code> defined inside.</p>
  
  <p>In the other TU, a degree of sanity must prevail: the function <code>a</code> must
  have the compatible structure types <code>struct r1</code> and <code>struct r2</code> visible
  in its global scope.</p>
  
  <p>Here's another example, but this one does not compile:</p>
  
  <pre><code>#include &lt;stdio.h&gt;
  
  struct r1;
  extern void z(struct r1 *r1p);
  extern void y(struct r1 *r1p);
  
  void y(struct r1 *r1p)
  {
      struct r2 { struct r1 *rn; int y; };
      struct r1 { struct r2 *rn; int z; };
      struct r2 p = { r1p, 1 };
      struct r1 q = { &amp;p, 2 };
      p.rn = &amp;q;
      printf("p.y = %d, q.z = %d\n", p.y, q.z);
  }
  
  void z(struct r1 *r1p)
  {
      struct r1
      struct r2 { struct r1 *rn; int y; };
      struct r1 { struct r2 *rn; int z; };
      struct r2 p = { r1p, 1 };
      struct r1 q = { &amp;p, 2 };
      p.rn = &amp;q;
      printf("p.y = %d, q.z = %d\n", p.y, q.z);
  }
  </code></pre>
  
  <p>The warnings from GCC 4.7.1 on Mac OS X 10.7.4 are:</p>
  
  <pre><code>structs3.c: In function 'y':
  structs3.c:13:10: warning: assignment from incompatible pointer type [enabled by default]
  structs3.c: In function 'z':
  structs3.c:22:12: warning: initialization from incompatible pointer type [enabled by default]
  structs3.c:22:12: warning: (near initialization for 'p.rn') [enabled by default]
  </code></pre>
  
  <p>Lines 13 is the assignment <code>p.rn = &amp;q;</code> in function <code>y</code> and line 23 is
  the attempt to define and initialize <code>struct r2 p</code> in function <code>z</code>.</p>
  
  <p>This demonstrates that within the functions, the <code>rn</code> element of <code>struct
  r2</code> is a pointer to the incomplete type <code>struct r1</code> declared at the
  global scope.  Adding a <code>struct r1;</code> as the first line of code inside
  the function would allow the code to compile, but the initialization
  referencing <code>r1p-&gt;rn</code> is derefencing a pointer to an incomplete type
  again (the incomplete type is the <code>struct r1</code> declared at the global
  scope).</p>
  
  <p>The function declarations and the preceding <code>struct r1;</code> line could
  appear in a header as an opaque type.  The list of supporting functions
  is incomplete; there'd need to be a way to get a pointer to an
  initialized <code>struct r1</code> to pass into the functions, but that's a detail.</p>
  
  <p>To make the code work in this second TU, the types for <code>struct r1</code> must
  be complete in the global scope before the functions are defined, and
  because of the recursive references, `struct r21 must also be complete.</p>
  
  <pre><code>#include &lt;stdio.h&gt;
  
  /* Logically in a 3-line header file */
  struct r1;
  extern void z(struct r1 *r1p);
  extern void y(struct r1 *r1p);
  
  /* Details private to this TU */
  struct r2 { struct r1 *rn; int y; };
  struct r1 { struct r2 *rn; int z; };
  
  void y(struct r1 *r1p)
  {
      struct r2 p = { r1p,     1 };
      struct r1 q = { r1p-&gt;rn, 2 };
      p.rn = &amp;q;
      printf("p.y = %d, q.z = %d\n", p.y, q.z);
  }
  
  void z(struct r1 *r1p)
  {
      struct r2 p = { r1p,     1 };
      struct r1 q = { r1p-&gt;rn, 2 };
      p.rn = &amp;q;
      printf("p.y = %d, q.z = %d\n", p.y, q.z);
  }
  </code></pre>
  
  <p>This process of defining the structures in the implementation file while
  leaving the type incomplete in the public header file can be repeated in
  multiple implementation files if necessary, though if more than one TU
  uses the complete structure definition, it would be better to place the
  definitions in a private header file shared only between the files that
  implement the structures.  I note that it does not matter whether the
  private header precedes or follows the public header.</p>
  
  <p>Maybe this was all obvious to you already.  I'd not needed to think it
  through in this level of detail before.</p>