4

I have a large codebase that recently moved from Microsoft's compiler to the Intel C++ Compiler. Our team's goal is compilation without warnings in the mainline. Since the switch, one instance of warning 167 has confounded me. If I compile the following code:

int foo(const int pp_stuff[2][2])
{
   return 0;
}

int foo2(const int pp_stuff[][2])
{
    return 0;
}


int main(void)
{
    int stuff[2][2] = {{1,2},{3,4}};

    foo(stuff);
    foo2(stuff);

    return 0;
}

The ICC will give me warnings:

1>main.c(17): warning #167: argument of type "int (*)[2]" is incompatible with parameter of type "const int (*)[2]"
1>        foo(stuff);
1>            ^
1>  
1>main.c(18): warning #167: argument of type "int (*)[2]" is incompatible with parameter of type "const int (*)[2]"
1>        foo2(stuff);

Why should this be a warning? It is common practice to pass a non-const variable as a const parameter, and the types & dimensions are identical.

To those who have marked this a duplicate question, I urge you to reconsider. If someone else encounters this warning, they would have to know that in C arguments are converted as if by assignment in prototyped functions, and then search for a question that is strictly about assignment. Even though the answer ends up being the same clause from C90/C99, the question is, I think, pretty different.

Phill
  • 65
  • 1
  • 7
  • why not use: int foo2(const int* pp_stuff) – Josh Petitt Feb 15 '13 at 21:40
  • @josh, because it's not as informative to other developers. When we pass around arrays of fixed dimensions, it's self-documenting to include the dimension in the declaration. It also self-enforces via compiler warnings/errors. – Phill Feb 15 '13 at 23:15

2 Answers2

2

Cast your variable as const when you pass it to the function that requires const.

foo( (const int (*)[2]) stuff );

Why can't I pass a char ** to a function which expects a const char **?

Similar question

Community
  • 1
  • 1
  • Thanks, I think the link answers my question. – Phill Feb 15 '13 at 19:44
  • So I think that it might be better practice to not use multidimensional arrays as arguments, and use pointer arrays instead, since in that case no cast would be required. – Phill Feb 15 '13 at 19:46
2

The value of stuff array is of type int (*)[2].

int foo(const int pp_stuff[2][2])

is equivalent to

int foo(const int (*pp_stuff)[2])

In the function call, it is as if you were assigning a value of type int (*)[2] to a variable of type const int (*)[2].

Arguments are converted as if by assignment in prototyped functions. And C let you assign two pointers if:

both operands are pointers to qualified or unqualified versions of compatible types, and the type pointed to by the left has all the qualifiers of the type pointed to by the right;

Here int (*)[2] and const int (*)[2] are not qualified/unqualified versions of the same type. The qualifier applies to int not to the pointer.

Use:

int foo(int (* const pp_stuff)[2])

if you want to make the pointer const and not the int elements.

ouah
  • 142,963
  • 15
  • 272
  • 331
  • Still I don't see a proper reasoning to _not_ pass an array of variable elements to a function which tells me that it won't vary the elements by making it const? – Jonas Schäfer Feb 15 '13 at 18:59
  • In this use case, the elements are exactly what I want to be `const`. To me this should be the same as passing an `int` argument to a `const int` parameter, which does not issue a warning. If I add declaration `int foo3(const int (*const pp_stuff)[2]) {return 0;}` and an associated call `foo3(p_stuff);` to `main()`, I get another 167 warning. (That version also triggers an MS intellisense error.) However, if I use `int foo3(const int *const pp_stuff[2]) {return 0;}` the warning goes away. – Phill Feb 15 '13 at 19:05
  • @Phill read the rule again, this is not the same. You can assign a `int *` to a `const int *` because `int` and `const int` are unqualified/qualified versions of the same type. This is not the case between `int (*)[2]` and `const int (*)[2]`. – ouah Feb 15 '13 at 19:10
  • @Phill also note that your `foo3` example is different to mine. – ouah Feb 15 '13 at 19:13
  • @ouah, got the difference, I had an extra const. However, even the corrected `int foo4(int (*const pp_stuff)[2])` causes a 167 warning. The FAQ linked by @Armin, I think, answers the question, even if I wish it weren't so. – Phill Feb 15 '13 at 19:48
  • Good if the FAQ helped you. Anyway the reason why you get the warning is explained here and for `foo4`, the program is strictly conforming. A compiler can always issue a warning but no warning is requested by C. – ouah Feb 15 '13 at 19:58