Meaning of asterisk as index of array in function parameter? [duplicate] - c

This question already has an answer here:
What does asterisk inside square bracket of array declaration mean in C [duplicate]
(1 answer)
Closed 6 years ago.
What is the meaning of * in function parameter when it is in the index of array in C?
int function(int a[*])

* is used inside [] only to declare function prototypes. Its a valid syntax. It's useful when you omit parameters name from the prototype like example below
int function(int, int [*]);
It tells the compiler that second parameter is a VLA and depends on the value of the first parameter. In the above example it's not worth of doing this. Take a look at a more useful example
int function(int, int [][*]);
This can't be possible to use VLA as a parameter in a function prototype, having unnamed parameters, without using * inside [].
6.7.6 Declarators
Syntax
1 declarator:
[...]
direct-declarator [ type-qualifier-list static assignment-expression ]
direct-declarator [ type-qualifier-listopt * ]
direct-declarator ( parameter-type-list )
direct-declarator ( identifier-listopt )

Paragraph 6.7.6.2/1 of the standard specifies that in an array-like declaration:
In addition to optional type qualifiers and the keyword static, the [ and ] may delimit an expression or *.
(emphasis added). Paragraph 4 of the same section explains:
If the size is * instead of being an expression, the array type is a variable length array type of unspecified size, which can only be used in declarations or type names with function prototype scope
Provided that your implementation supports VLAs, that's what you have. The function is declared to accept an argument that is a (pointer to the first element of) a variable-length array of unspecified length.
As #WeatherVane observes in comments, however, C2011 makes VLA support optional (whereas it was mandatory in C99). For an implementation that does not support VLAs, the code is syntactically incorrect.
You can check for VLA support via the preprocessor, somewhat:
#if __STDC__
#if __STDC_VERSION__ == 199901L || ( __STDC_VERSION__ >= 201112L && ! __STDC_NO_VLA__ )
// VLAs are supported (or the implementation is non-conforming)
#else
// VLAs are not supported
// (unless the implementation provides VLAs as an extension, which could,
// under some circumstances, make it non-conforming)
#endif
#else
// a C89 or non-conforming implementation; no standard way to check VLA support
#endif

Related

What does "parenthesized declarators" mean in C syntax

The C Standard specifies some translation limits. I cannot understand the following two:
12 pointer, array, and function declarators (in any combinations) modifying an arithmetic,
structure, union, or void type in a declaration
63 nesting levels of parenthesized declarators within a full declarator
Can someone explain and give simple examples for:
declarator modifying a declaration and
parenthesized declarators within a full declarator
C 2018 2.7.6 specifies declarators, including showing the grammatical definition of a declarator as:
declarator: pointeropt direct-declarator
direct-declarator:
        identifier
        ( declarator )
        direct-declarator [ … ]
        direct-declarator ( … )
pointer:
        * type-qualifier-listopt
(The syntax used for this grammar is briefly discussed in 6.1. Even more briefly, “direct-declarator:” means, when the compiler is looking for a direct-declarator, it will accept any of the options listed on the following lines. The subscript “opt” means an item is optional. I have consolidated multiple options in the original to “…” since the details are unimportant in this question. For example, array declarators may be empty or may contain an assignment expression and may have static, and so on.)
In int x;, x is a declarator. The declaration causes x to be declared as an int.
In int *x, *x is a declarator. It causes x to be declared as an int *. So it has modified the declaration.
In int (*x[3][4])(float, char);, x is a declarator (because it is a direct-declarator that is an identifier). It is inside an array declarator (a term shown in 6.7.6.2 to refer to the options with [ and ] above), x[3]. That is inside another array declarator, x[3][4]. That is a direct-declarator inside a pointer declarator (shown in 6.7.6.1 to refer to the pointer option above), *x[3][4]. That is inside a parenthesized declarator, (*x[3][4]) (a term that is not explicitly defined but is clear). And that is inside a function declarator (6.7.6.3), (*x[3][4])(float, char). Thus, this declaration has five nested levels of declarators modifying the int type in the declaration, four of which are pointer, array, or function declarators (one is a parenthesized declarator). It declares x to be an array of 3 arrays of 4 pointers to a function taking float and char and returning int.
At this point, the “63 nesting levels of parenthesized declarators within a full declarator” should be clear. int (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((x))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); has 63 nested levels of parenthesized declarators within a full declarator. This does not normally arise in direct drafting of a declaration, but construction of declarations by use of various macros might give rise to multiple levels of parentheses.
The standard is treating pointer, array, and function declarators as something the compiler must keep track of, and is therefore subject to a modest limit of 12 nested levels, whereas parentheses are a superficial grammatical construction that need be tracked only during parsing and can then be discarded internally, and so are less burdensome on a compiler and have a more generous limit.

C declarator understanding

I am reading about declarators in C99 ISO Standard and I am struggling to understand the following passage:
5 If, in the declaration ”T D1”, D1 has the form
    identifier
then the type specified for ident is T.
6 If, in the declaration “T D1”, D1 has the form
    ( D )
then ident has the type specified by the declaration “T D”. Thus, a declarator in parentheses is identical to the unparenthesized declarator, but the binding of complicated declarators may be altered by parentheses.
You omitted an important previous paragraph:
4 In the following subclauses, consider a declaration
    T D1
where T contains the declaration specifiers that specify a type T (such as int) and D1 is a declarator that contains an identifier ident. The type specified for the identifier ident in the various forms of declarator is described inductively using this notation.
So, when we get to paragraphs 5 and 6, we know the declaration we are considering contains within it some identifier which we label ident. E.g., in int foo(void), ident is foo.
Paragraph 5 says that if the declaration “T D1” is just ”T ident”, it declares ident to be of type T.
Paragraph 6 says that if the declaration “T D1” is just ”T (ident)”, it also declares ident to be of type T.
These are just establishing the base cases for a recursive specification of declaration. Clause 6.7.5.1 goes on to say that if the declaration “T D1” is ”T * some-qualifiers D” and the same declaration without the * and the qualifiers, ”T D” would declare ident to be “some-derived-type T” (like “array of T” or “pointer to T”), then the declaration with the * and the qualifiers declares ident* to be “some-derived-type some-qualifiers pointer to T”.
For example, int x[3] declares x to be “array of 3 int”, so this rule in 6.7.5.1 tells us that “int * const x[3] declares x to be “array of 3 const pointer to int”—it takes the “array of 3” that must have been derived previously and appends “const pointer to” to it.
Similarly, clauses 6.7.5.2 and 6.7.5.3 tell us to append array and function types to declarators with brackets (for subscripts) and postfix parentheses.
In the quoted definitions, T is a type (e.g. int or double or struct foo or any typedef name), and D1 is a declarator.
Declarators may be arbitrarily complex, but are constructed from a small number of simple steps. They mention that it is defined inductively, which is another way of saying it has a recursive defintion.
The simplest declarator is just an identifier name, such as x or foo. So T could be int and D1 could be x.
It then goes on to say that a declarator may be parenthesized, e.g. (x) or ((x)) etc. These are degenerate cases, and are both equivalent to just x, but there are times when parentheses are needed to produce the desired grouping. For example, the declarators *x[10] and (*x)[10] mean quite different things. The former is equivalent to *(x[10]) and is an array of pointers, while the latter is a pointer to an array.
There is more to it (arrays, pointers, functions, etc.), but this covers the portion referenced in the question.
In long int *ident[4]; (array (4) of pointer to long int) long int is the specifier list, *ident[4] is the declarator.
You can put the declarator in parentheses without changing semantics:
long int (*ident[4]);, but in a more complex declaration such as
long int (*ident[4])[5]; (array (4) of pointer to array (5) of long int), the parentheses affect binding as without them, long int *ident[4][5]; would be interpreted as array (4) of array (5) of pointer to long int.
It works this way because the declarator part can recursively encompass another declarator and so on.
From the old C manual (it got a bit more indirect in later standardized Cs, but the basic principle is the same):
declarator:
identifier
* declarator
declarator ( )
declarator [ constant-expression opt ]
( declarator )
To put it in another way, C declarators are a way to prefix pointer-to/function-returning/array-of to some specifier list (e.g., long int) and these can be combined to create a chain.
Normally, in the creation of that chain, the suffixes (()=function returning, []=array of) bind tighter than the */pointer-to prefix. You can use parentheses to override this and force * (or several of them) to bind now without it getting overpowered by a []/() suffix.
E.g.:
long int *ident[4][5]; //array (4) of array (5) of pointer to long int
//the suffixes win over the `*` prefix
long int (*ident[4])[5]; //array (4) of pointer to array (5) of long int
//the parens force `pointer to` right after `array (4)`
//without letting the `[]` suffix overpower the pointer-to/`*` declarator prefix
P.S.:
C disallows arrays of functions and functions returning functions or arrays. These are both nicely expressible in the grammar but C's semantic check will want you to but a pointer-to link in there to prevent these.
cdecl.org may be very helpful if you want to play with these, and perhaps even more so because it doesn't do said semantic check, therefore allowing you even things like int foo[]()(); (array of function returning function returning int), which nicely demonstrate how the grammar works, even though a C compiler would reject them.
...binding of complicated declarators
This is a very nice hint in the specs.
The rule itself is really hard to analyze because of it's recursiveness. Also the relation and parts of declaration and declarator are relevant.
The results are:
() and [] are the innermost direct-declarator parts, declaring (directly by symbol) functions and array names to the left
* declares a name as pointer on the right
(...) is needed for...complicated cases, to change the default association.
The grouping parens lead you on your way from inside (identifier) to outside (type specifier on the left, say "int").
In the end it is all about the pointer symbol * and what it refers to. The reformulated (brackets mean optional, not array here!) syntax is:
declarator: [* [qual]] direct-declarator
direct-declarator: (declarator)
foo() is a DD (direct declarator)
*foo is a declarator. ("indirect" by deduction)
*foo() is *(foo()). foo stays a function, () and [] bind strongest. The * is the return type.
(*foo)() makes foo a pointer. One to a function.
BTW this also explains why in a list of declarator.
int const * a, b
both are const int, but only a is a pointer
The const belongs to int and the star only to a. This makes it more clear,
const int x, *pi
But this already is borderline obfuscation. Like modern poetry. Good for certain occasions.
Even without parens there is a slight U-turn in parsing. But this is natural:
3 2 0 1
int *foo()
This standard situation (and similar ones) had to be simple. Also the famous multidim arrays like int a[10][10][10].
3 1 0 2
int (*foo)()
Here the parens force "foo" to be what is on the left side (a pointer).
Complicated Declarations have their own chapter in K&R C book.
This is sort of the simplest complicated declaration:
int (*(*foo)[])()
It debugs to abstract type:
int (*(*)[])()
With (*) replaced:
int (*F[])()
The missing array size gives compiler warning - "assuming one element".
As abstract type:
int (*[])()
But:
int *G[]()
--> error: declaration of 'G' as array of functions
Yes, you can, even recursively, but with the * indirection and parens. This makes an onion of parens with the identifeir in the middle, stars on the left and [] and () on the right.
The C11 specs has this monster. The ... declare variadic args:
int (*fpfi(int (*)(long), int))(int, ...)
With all params removed:
int (*fpfi())()
Simply a function returning a pointer. One to a function returning int.
But the first param of fpfi is a function itself - a pointer to function with return type and its own params:
int (*)(long)
Non-abstractly:
int (*foo)(long)
A pointer to a function that "converts" a long to int, formally.
That is the param. Only. The return value is also a function pointer, and the pointed-to function's params and return type are outermost. Dropping the whole inner function thing (int (*)(long), int):
int (*pfi)(int, ...)
Or more generic/incomplete:
int (*pfi)()
"T (D)" Onion Rule
So this onion-game repeats itself. Inside-out and right-left-right-left between [], () and *. Syntax is not the problem, but semantics.

C11: how does fixed-length array declaration fit in the C11 standard's specification?

The C11 standard (N1548) section 6.7.6 set forth the specifications of a declarator.
In my understanding (see this answer about dissecting a C declaration), an array declaration int * arr[5]; has two parts: (a) declaration specifiers int, and (b) declarator * arr[5]. My problem is how to interpret the declarator part according to the C11 standard.
The standard says:
Ok, so * clearly corresponds to the "pointer" part. Therefore, arr[5] must correspond to the "direct-declarator" part. However, in the expansion of "direct-declarator" in this standard, it seems there is not an entry that matches arr[5] -- because it seems the constant expression 5 in the bracket does not match with "type-qualifier-list" or "assignment-expression".
So how does this declaration fit in the C11 standard's specification?
5 is assignment-expression.
If you look at the definition of assignment-expression, one of it is conditional-expression. And one definition for that is logical-OR-expression. By tracking down this definition chain, you'll eventually reach primary-expression, for which on one definition is constant.

an error about C struct array in formal parameter

I have got the following code:
struct student_info;
void paiming1(struct student_info student[]);
struct student_info
{
int num;
char name[6];
};
The IDE gives an error
error: array type has incomplete element type ‘struct student_info’
void paiming1(struct student_info student[]);
But if I use void paiming1(struct student_info *student); it works OK. Why is that? I am using GCC.
С language unconditionally requires array element type in all array declarations to be complete. Period.
6.7.6.2 Array declarators
Constraints
1 [...] The element type shall not be an incomplete or function
type. [...]
No exception is made for array declarations used in function parameter lists. This is different from C++ - the latter drops this completeness requirement for function parameter lists
struct S;
void foo(struct S[]); // OK in C++, invalid in C
Considering that in parameter list declaration type T [] is later adjusted to type T * anyway, this requirement might appear to be excessive. (And this is why C++ relaxed it.) Nevertheless, this restriction is present in C language. This is just one of the quirks of C language.
As you already know, you can explicitly switch to the equivalent
void paiming1(struct student_info *student);
form to work around the issue.
Careful reading of the standard makes it clear that in C99 and C11 the declaration is supposed to be a constraint violation. C11 6.7.2.6 Array declarations p1
In addition to optional type qualifiers and the keyword static, the [ and ] may delimit an expression or *. If they delimit an expression (which specifies the size of an array), the expression shall have an integer type. If the expression is a constant expression, it shall have a value greater than zero. The element type shall not be an incomplete or function type. The optional type qualifiers and the keyword static shall appear only in a declaration of a function parameter with an array type, and then only in the outermost array type derivation.
Since this contains references to the * that is valid only in function declarations that are not definitions, and nowhere else, the constraints as whole needs to be taken as applying to parameters.
For C90 the case is more complicated. This is actually discussed in C90 Defect Report 47 from 10 December, 1992.
2 of the 6 declarations given there are
/* 1. */ struct S;
/* 3. */ struct S *g(struct S a[]) { return a; }
and the defect report asks if these are strictly-conforming. It must be noted that unlike the question, these are prototypes that are part of definition rather than just declaration.
Nevertheless, the standard committee responds by saying that
The struct S is an incomplete type (subclause 6.5.2.3, page 62, lines 25-28). Also, an array of unknown size is an incomplete type (subclause 6.5.4.2, page 67, lines 9-10). Therefore, arrays of either of the above are not strictly conforming (subclause 6.1.2.5, page 23, lines 23-24). This makes declarations 3, 4, and 6 not strictly conforming. (But an implementation could get it right.)
As an aside, array parameters are adjusted to pointer type (subclause 6.7.1, page 82, lines 23-24). However, there is nothing to suggest that a not-strictly-conforming array type can magically be transformed into a strictly conforming pointer parameter via this rule.
The types in question can be interpreted two different ways. (Array to pointer conversion can happen as soon as possible or as late as possible.) Hence a program that uses such a form has undefined behavior.
(emphasis mine)
Since this has not been clarified in writing since 1992, we must agree that the behaviour is undefined and therefore the C standard imposes no requirements, and a compiler that successfully compiles this this can still conform to C90.
The committee also states that there is no constraint violation in C90, therefore a C90 conforming compiler need not output any diagnostics.
I've edited the answer; I previously claimed that this would apply to C99 and C11 alike, but the text was changed in C99 as above, therefore this is a constraint violation in C99, C11.
Compiler doesn't know anything about size of struct student_info until it is declared. This should work:
struct student_info
{
int num; //学号
char name[6]; //姓名
char sex[5]; //性别
char adress[20]; //家庭住址
char tel[11]; //电话
int chinese,math,english,huping,pingde,jiaoping,paiming1,paiming2;
double ave,zhongping;
};
void paiming1(struct student_info student[]);
void paiming2(struct student_info student[]);
When you declare it as a pointer using *, compiler knows the size of the argument (its an address).

Rationale for the C11 _Atomic specifier-vs-qualifier syntax irregularity?

There is a related "what" question here: C11 grammar ambiguity between _Atomic type specifier and qualifier
What I'm interested is why, since the C11 rationale hasn't been published yet, and this seems needlessly complex.
The grammar includes both of these (and resolves the ambiguity in favor of shifting the ( rather than reduce (which would otherwise be in lookahead if followed by a declarator or abstract-declarator)), reachable from declaration-specifiers or specifier-qualifier-list:
atomic-type-specifier: _Atomic ( type-name )
type-qualifier: _Atomic
This leads to the following code:
int i1;
int (i2); // valid, same as i1 - usually seen in the context of pointer-to-function or pointer-to-array
int _Atomic a1;
int _Atomic (a2); // invalid
_Atomic (int) a3; // valid, same as a1
Thoughts:
_Atomic must not modify an array or function. Barring redundant parentheses around a declarator, this means it would be valid to #define _Atomic(x) x _Atomic (if it were legal to #define keywords of course).
When it occurs as a qualifier, _Atomic is the same syntactical part as const, and C programmers are already used to putting const on the correct side, so it can't be for "ease of use".
The rationale is found in N1485:
The _Atomic keyword also can also be used in the form _Atomic(T),
where T is a type, as a type specifier equivalent to _Atomic T.
Thus, _Atomic(T) x, y; declares x and y with the same type, even
if T is a pointer type. This allows for trivial C++0x compatibility
with a C++ only _Atomic(T) macro definition as atomic<T>.

Resources