Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why use "[*]" instead of "[]" in function prototype?

Here is what is it written as rationale for adding the fancy * star syntax for declaring array types inside function prototypes - just for clarification before we get into the question:

A function prototype can have parameters that have variable length array types (§6.7.5.2) using a special syntax as in int minimum(int,int [*][*]); This is consistent with other C prototypes where the name of the parameter need not be specified.

But I'm pretty confident that we can have the same effect by simply using only ordinary arrays with unspecified size like this (here re-writing the function example named minimum given above in the quote with what I believe exactly the same functionality (except for using size_t instead of int as first parameter which isn't that important in the case)):

#include <stdio.h>


int minimum(size_t, int (*)[]);

int (main)()
{
    size_t sz;

    scanf("%zu", &sz);

    int vla[sz];

    for(size_t i = 0; i < sz; ++i)
        vla[i] = i;

    minimum(sizeof(vla) / sizeof(*vla), &vla);

    int a[] = { 5, 4, 3, 2, 1, 0 };

    minimum(sizeof(a) / sizeof(*a), &a);
}


int minimum(size_t a, int (*b)[a])
{  
    for(size_t i = 0; i < sizeof(*b) / sizeof(**b); ++i)
        printf("%d ", (*b)[i]);

    return printf("\n");
}

Because I'm pretty sure that there was some place in the standard stating that 2 arrays are compatible only if their size are equal and no-matter if they are variable or not.

My point is also confirmed by the fact that the minimum definition wouldn't complain for "conflicting types" as it would if some of it's parameters had incompatible types (which I don't think is the case as both of those arrays have size which is unspecified at compile-time - I refer to the second parameter of minimum).

OK besides - can you point me 1 single use-case for [*] that can not be replaced using ordinary unspecified size arrays?

The above code compiles without any warnings using both clang and gcc. It also produces the expected output.

For anyone who doesn't know C (or anyone who thinks that he/she knows it) - function parameter of type array is implicitly transformed to "pointer to its elements type". So this:

int minimum(int,int [*][*]);

Gets adjusted to:

int minimum(int,int (*)[*]);

And then I'm arguing that it could be also written as:

int minimum(int,int (*)[]);

Without any consequences and with the same behavior as the 2 forms above. Thus making the [*] form obsolete.

like image 901
AnArrayOfFunctions Avatar asked Jun 06 '16 13:06

AnArrayOfFunctions


2 Answers

OK besides - can you point me 1 single use-case for [*] that can not be replaced using ordinary unspecified size arrays?

This would be the case, when you pass three-dimensional VLA array:

int minimum(size_t, int [*][*][*]);

This can be written as:

int minimum(size_t, int (*)[*][*]);

or even using an array of unspecified size:

int minimum(size_t, int (*)[][*]);

But you have no possibility to omit nor get around of the last indice, thus it has to stay as [*] in a such declaration.

like image 131
Grzegorz Szpetkowski Avatar answered Nov 14 '22 22:11

Grzegorz Szpetkowski


[] can only be used as the leftmost "dimension specifier" of a multidimensional array, whereas [*] can be used anywhere.

In function parameter declarations, the leftmost (only!) [...] is adjusted to (*) anyway, so one could use (*) in that position at the expense of some clarity.

One can omit the dimension in the next-to-leftmost [...], leaving the empty brackets. This will leave the array element type incomplete. This is not a big deal, as one can complete it close to the point of use (e.g. in the function definition).

The next [...] needs a number or * inside which cannot be omitted. These declarations

int foo (int [*][*][*]);
int foo (int (*)[*][*]);
int foo (int (*)[ ][*]);

are all compatible, but there isn't one compatible with them that doesn't specify the third dimension as either * or a number. If the third dimension is indeed variable, * is the only option.

Thus, [*] is necessary at least for dimensions 3 and up.

like image 22
n. 1.8e9-where's-my-share m. Avatar answered Nov 14 '22 23:11

n. 1.8e9-where's-my-share m.