Just was looking something up in the ISO/IEC9899 When I stumbled on this:
6.7.6 Type names
[...]
Semantics
2 In several contexts, it is necessary to specify a type. This is accomplished using a type name, which is syntactically a declaration for a function or an object of that type that omits the identifier.128) 3 EXAMPLE The constructions
(a) int (b) int * (c) int *[3] (d) int (*)[3] (e) int (*)[*] (f) int *() (g) int (*)(void) (h) int (*const [])(unsigned int, ...)
name respectively the types (a) int, (b) pointer to int, (c) array of three pointers to int, (d) pointer to an array of three ints, (e) pointer to a variable length array of an unspecified number of ints, (f) function with no parameter specification returning a pointer to int, (g) pointer to function with no parameters returning an int, and (h) array of an unspecified number of constant pointers to functions, each with one parameter that has type unsigned int and an unspecified number of other parameters, returning an int.
What most confused me was:
(e) pointer to a variable length array of an unspecified number of ints
The others I can understand more or less. But what is the use of a pointer to a VLA of unspecified number of 'ints'?
And is there even a need for compiler's to support the syntax of
int foo[*];
?
EDIT for clarification
This Question primaly aims on "Is it even neccessary to support this for a compiler?". Whilest this post ANSI-C grammar - array declarations like [*] et alii clearly improved my knowledge. There is still no answer for: Why does the compiler need to know if the parameter of the prototype just is a address containing unknown size. as with simply doing int foo[]
or it will be unspecified size?
So is this realy neccessary to be supported? And if not so, why the standard even is implementing this semantic?
int: As the name suggests, an int variable is used to store an integer. float: It is used to store decimal numbers (numbers with floating point value) with single precision. double: It is used to store decimal numbers (numbers with floating point value) with double precision.
Answer: * Operator is used as pointer to a variable. Example: * a where * is pointer to the variable a. & operator is used to get the address of the variable.
While * means the address of a variable in C programming language, what does ** mean then? Actually, & means the address of a variable. * means the value at an address, which also known as dereferencing. In that sense, ** just is dereferencing twice.
&,* Operator: Pointer operator & returns the address of a variable. For example &a; will give the actual address of the variable. Pointer operator * is a pointer to a variable.
Why does the compiler need to know if the parameter of the prototype just is a address containing unknown size. as with simply doing int foo[] or it will be unspecified size?
The compiler doesn't need to "know" anything, it's a tool.
The difference between int (*)[*]
and int[]
is about the same as between int (*)[5]
and int[]
. If you agree that the latter pair is not interchangeable, then the former isn't either.
In pre-C99, the way to specify an array of unknown number of T
elements is T[]
. This is an incomplete type, which means you cannot have an array of T[]
. There is no T[][]
. Inside a function declarator, T[]
means the same as T*
. OTOH T[*]
is a variable-length array, which is different from an array of unknown number of elements. You can have an array of variable-size arrays, i.e. there is T[*][*]
. The syntax you are asking about is necessary to support this variable-size-array type. Luckily you are not asking why we need different types, because the answer would be really long-winded, but here's my stab at it.
The purpose of types is two-fold. First, types are needed for object code generation (things like a++
typically generate different object code, depending on the type of a
). Second, types are needed for type-checking (things like a++
may be allowed or not depending on the type of a
).
The [*]
types are only allowed in function declarators that are not parts of function definitions. So code generation and is not relevant here. This leaves us with type checking. Indeed,
int foo(int, int (*)[*]); int bar(int, int (*)[5]); int main () { int a; int aa[5]; int aaa[5][5]; foo(1, &a); // incorrect, `&a` is `int*`, `int*` and `int (*)[*]` are different bar(1, &a); // incorrect, `&a` is `int*`, `int*` and `int (*)[5]` are different foo(5, aa); // incorrect, `aa` is `int*` (!), `int*` and `int (*)[*]` are different bar(5, aa); // incorrect, `aa` is `int*` (!), `int*` and `int (*)[5]` are different foo(5, &aa); // correct bar(5, &aa); // correct foo(5, aaa); // correct bar(5, aaa); // correct }
If we are agree on which calls to bar
are correct and which are not, we must agree also on calls to foo
.
The only remaining question is, why int foo(int m, int (*)[m]);
is not enough for this purpose? It probably is, but the C language does not force the programmer to name formal parameters in function declarators where parameter names are not needed. [*]
allows this small freedom in case of VLAs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With