title: Strange warning in a C function const multidimensional-array argument
body: <p>I'm getting some strange warnings about this code:</p>
  
  <pre><code>typedef double mat4[4][4];
  
  void mprod4(mat4 r, const mat4 a, const mat4 b)
  {
  /* yes, function is empty */
  }
  
  int main()
  {
      mat4 mr, ma, mb;
      mprod4(mr, ma, mb);
  }
  </code></pre>
  
  <p><code>gcc</code> output as follows:</p>
  
  <pre><code>$ gcc -o test test.c
  test.c: In function 'main':
  test.c:13: warning: passing argument 2 of 'mprod4' from incompatible pointer
  type
  test.c:4: note: expected 'const double (*)[4]' but argument is of type 'double
  (*)[4]'
  test.c:13: warning: passing argument 3 of 'mprod4' from incompatible pointer
  type
  test.c:4:
  note: expected 'const double (*)[4]' but argument is of type 'double
  (*)[4]'
  </code></pre>
  
  <p>If I define the function as:</p>
  
  <pre><code>void mprod4(mat4 r, mat4 a, mat4 b)
  {
  }
  </code></pre>
  
  <p>Or defining matrices in main as:</p>
  
  <pre><code>mat4 mr;
  const mat4 ma;
  const mat4 mb;
  </code></pre>
  
  <p>Or call the function in main as:</p>
  
  <pre><code>mprod4(mr, (const double(*)[4])ma, (const double(*)[4])mb);
  </code></pre>
  
  <p>Or even defining <code>mat4</code> as:</p>
  
  <pre><code>typedef double mat4[16];
  </code></pre>
  
  <p>Makes the warning go away. What is happening here? Am I doing something invalid?</p>
  
  <p>The gcc version is 4.4.3, if relevant.</p>
  
  <p>I also posted on gcc bugzilla: <a href="http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47143" rel="nofollow noreferrer">http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47143</a></p>
  
  <p>My current workaround is making ugly macros that cast stuff for me:</p>
  
  <pre><code>#ifndef _NO_UGLY_MATRIX_MACROS
  
  #define mprod4(r, a, b) mprod4(r, (const double(*)[4])a, (const double(*)[4])b)
  
  #endif
  </code></pre>
  
  <hr>
  
  <p>Answer from Joseph S. Myers on gcc bugzilla:</p>
  
  <blockquote>
    <p>Not a bug.  The function parameters
    are of type "pointer to array[4] of
    const double" because const on an
    array type applies to the element
    type, recursively, and then the
    outermost array type, only, of a
    parameter of array type decays to a
    pointer, and the arguments passed are
    of type "pointer to array[4] of
    double" after array-to-pointer decay,
    and the only case where qualifiers are
    permitted to be added in assignment,
    argument passing etc. is qualifiers on
    the immediate pointer target, not
    those nested more deeply.</p>
  </blockquote>
  
  <p>Sounds pretty confusing to me, like the function expects:</p>
  
  <pre><code>pointer to array[4] of const doubles
  </code></pre>
  
  <p>and we are passing</p>
  
  <pre><code>pointer to const array[4] of doubles
  </code></pre>
  
  <p>intead.</p>
  
  <p>Or would it be the inverse? The warnings suggest that the function expects a:</p>
  
  <pre><code>const double (*)[4]
  </code></pre>
  
  <p>which seems to me more like a</p>
  
  <pre><code>pointer to const array[4] of doubles
  </code></pre>
  
  <p>I'm really confused with this answer. Could somebody who understands what he said clarify and exemplify?</p>