Octan
Octan

Reputation: 348

Pointer to const in function call

I’ve an integer array int foo[3] and I want to pass it to another function. I would like to accomplish two things:

The function I’ve defined is:

void print_foo(const int(*const foo)[3]) {

    // Print the second integer
    printf("%d\n", (*foo)[1]);
}

And I call it as:

int foo[3] = {1, 2, 3};

print_foo(&foo);

When I compile it with MinGW’s gcc I get the warning:

warning: passing arg 1 of `print_foo` from incompatible pointer type

I would like to understand what am I doing wrong.

Note: I can hide the warning declaring the function without the first const as:

void print_foo(int(*const foo)[3])

But this seems like a workaround as I want not only the pointer address to be constant but also the contents of the memory (that’s the reason of the two const).

Upvotes: 3

Views: 273

Answers (2)

Serge Ballesta
Serge Ballesta

Reputation: 148870

Interestingly enough, I could compile the following code with CLang versions 3.4.1 and 6.0.0 with no warnings:

#include <stdio.h>

void print_foo(const int (* const foo)[3]) {
    printf("%d - size: %lu\n", (*foo)[1], sizeof(*foo));
}
int main() {
    int foo[3] = {1,2,3};
    print_foo(&foo);
    return 0;
}

Output is 2 - 12 on my 32 bits system, which proves that sizeof(*foo) has the expected value.

But I would say that gcc is correct here, and that Clang allows it as an extension.

The standard (draft n1570 for C11) says at 6.2.7 Compatible type and composite type §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 and in 6.7.3 Type qualifiers § 10

For two qualified types to be compatible, both shall have the identically qualified version of a compatible type

So types need to have the same constness to be compatible.

But passing parameters in a function call has the same semantics as an assignment, and 6.5.16.1 Simple assignment says in its constraints:

One of the following shall hold:
...
the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) 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

So ok, it is allowed to assign an int (*)[3] to an int (const *)[3] even if they are not compatibles.

But int [3] and const int[3] are different types, so you cannot assign an int (*)[3] to a const int (*)[3] nor to a const int (const *)[3].

What you want makes sense, but I cannot imagine a conformant way to declare it.

Upvotes: 2

bruno
bruno

Reputation: 32586

just do that :

#include <stdio.h>

// note can also use "const int foo[3]" but in that
// case 3 is nothing more than a comment for a reader
void print_foo(const int foo[])
{
  // Print the second integer
  printf("%d\n", foo[1]);
}

int main()
{
  int foo[3] = {1, 2, 3};

  print_foo(foo);
}

the array is already given by address

Upvotes: 3

Related Questions