0

The following program compiles in gcc but not g++:

    void foo(int (*x)[])
    {
        // do something
    }

    int main()
    {
        int x[3];

        foo(&x);  // g++ error: cannot convert ‘int (*)[3]’ to ‘int (*)[]’

        return 0;
    }

I am trying to use a library written in ANSI C, so I have no control over the interface of foo.

Why is this valid C and not valid C++ has been discussed in this QA. My question is: how can I call a function foo with such a declaration from C++?

Hugo Burd
  • 301
  • 1
  • 4
  • 12
  • 1
    What do you think `int(*)[]` is doing "better" than simply `int*` ? – Ben Voigt Jul 22 '20 at 16:42
  • 1
    I can't speak to the legality of that in C, but a C++ compiler sees your statement `foo(&x)` as you passing an array of references, vs your definition of `foo(int (*x)[])` which accepts an array of ints. That's why no C++ compiler will compile your code in the example. – alteredinstance Jul 22 '20 at 16:44
  • 2
    When you have a pointer to an array, the size of the array is part of the type. You can't have "pointer to any array". – Some programmer dude Jul 22 '20 at 16:44
  • @Ben Voigt I'm calling a library written in ANSI C from C++ and I don't have any control over the interface. – Hugo Burd Jul 22 '20 at 16:44
  • @alteredinstance Looks like a pointer to an array of three ints to me, not an array of references. – Christian Gibbons Jul 22 '20 at 16:45
  • I suggest understanding the difference between 'pointer to array' and 'array of pointer': [link](https://stackoverflow.com/questions/859634/c-pointer-to-array-array-of-pointers-disambiguation) – b00rt00s Jul 22 '20 at 16:45
  • @ChristianGibbons `x` by itself is already a pointer to an array, when you reference it as `&x` the compiler sees a "reference to a pointer", which is illegal in the context of `foo(int (*x)[])`. I think `g++ error: cannot convert ‘int (*)[3])’` makes it clear that the compiler sees `&x` as a reference to an array of pointers, and not a reference to an `int` array. My understanding isn't perfect though so I could be wrong here. – alteredinstance Jul 22 '20 at 16:50
  • 3
    @alteredinstance `x` is an array, not a pointer to one, so, `&x` is indeed a pointer to that array. There's no reference nor array of pointers involved here. – Quentin Jul 22 '20 at 16:52
  • The function should take 'int (*x)[3])' https://godbolt.org/z/jxr587 – b00rt00s Jul 22 '20 at 16:52
  • @alteredinstance No, `x` is the array itself, which when passed in as an argument of a function will decay to a pointer to an int (not a pointer to an array). By using the address-of unary operator `&`, you are getting a pointer to `x`, which is of type `int[3]`, so the pointer will be of type `int (*)[3]`, or in word-form, a pointer to an array of 3 ints. – Christian Gibbons Jul 22 '20 at 16:53
  • 1
    The duplicate answers one of my questions but not the other. I will ask a new question focusing on how to call a function of this declaration from C++. – Hugo Burd Jul 22 '20 at 16:55
  • 2
    @HugoBurd I'll reopen, you can edit – Antti Haapala -- Слава Україні Jul 22 '20 at 16:57
  • @Antti Haapala thanks for the edit – Hugo Burd Jul 22 '20 at 17:03
  • In C, the `&x` in `main` has type `int (*)[3]`. The `x` parameter in `foo` has type `int (*)[]` which is a pointer to an incomplete array of `int` type. It is legal in C, but `foo` cannot do much with `x` apart from convert its value to some other type. For example, it could convert it back to the type `int (*)[3]`. It could also convert it to the type `int (*)[42]` which would be a very dangerous thing to do. The entire construct is best avoided, IMHO. – Ian Abbott Jul 22 '20 at 17:08

1 Answers1

2

The following program compiles ... not g++:

This is because g++ compiles in the C++ language. And the shown program is ill-formed in the C++ language.

In particular, the problem is that the function parameter is a pointer to an array of unknown bound, but the passed argument is a pointer to an array of length 3. And latter is not implicitly convertible to the former.

So how does one get a pointer to an unspecified array in C++ anyway?!

Example:

extern int arr_ext[ ];
       int arr_3  [3];

int (*ptr)[] = &arr_ext;
ptr          = reinterpret_cast<int (*)[]>(&arr_3); // †

† In C++ using this reinterpreted pointer is probably technically UB in any other way than to reinterpret back as pointer to array of length 3, but if the use happens within the C library, who knows... Rules across language boundary are sometimes murky.


By contrast in C, a pointer to one type is implicitly convertible to a pointer to another compatible type. And arrays of unknown bound are compatible with an array of any size, of same element type.


There appears to be an active issue to allow same implicit conversion in C++: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4325.html#118

eerorika
  • 232,697
  • 12
  • 197
  • 326