10

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.

1
  • 3
    Why the down votes? This is a very good question and the code is a MCVE. Commented May 24, 2018 at 12:35

3 Answers 3

8

С 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.

Sign up to request clarification or add additional context in comments.

11 Comments

So every existing C99 compiler on the market is not conforming then? Because I don't think I've seen any compiler which does not accept empty [] before adjustment to pointer. I think this is the root of the problem: allowing empty [] while at the same time not allowing objects of incomplete type. Supposedly because there was an industry de facto standard established pre-C99, since C90 didn't specify the behavior. So the compilers try to eat the cake and keep it at the same time.
@Lundin: Could you please clarify what you mean? I don't see any non-conformance here. int[] is accepted because of the rule you quoted yourself (competeness is checked after adjustment and int * is complete). struct S[] in my example is rejected because of a different, higher-level rule: the array declaration is flat-out invalid.
Adjustments play no role in rejection of struct S[] whatsoever. We don't even get to that point. struct S[] is invalid immediately, by itself, regardless of context. If is invalid in any context.
It all boils down to whether the check if the declaration is incomplete happens before or after array adjustment. Just because C99 added a clarification that arrays cannot have incomplete type elsewhere, there is nothing saying that the check against 6.7.6.2 happens before array adjustment. This order is what I thought I had found in the standard, but apparently it is not defined. Either this check happens before array adjustment, and then both struct S[] and int i[] are invalid. Or it happens after array adjustment, and then they are both valid. Here gcc behaves inconsistently.
The point being: the compiler can't just do a check if an element of the array is of incomplete type, it has to check if the array in itself is complete or not at the very same time. Anything else would be quite irrational.
|
6

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

  1. 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.

3 Comments

The answer is incorrect. The comments in the old DR#47 are based on C89/90, which indeed has no constraint requiring array element type to be complete. However, C99 added additional constraints on array declarations (6.7.5.2). The corresponding constraint is quoted in my answer. The original code contains a full-blown constraint violation. A compiler that issues no diagnostic for this code is broken. "Since this has not been clarified in writing since 1992..." - this just does not make sense. It has been well-clarified in C99.
@AnT I am referring to whether or not the array type should be considered before or after the conversion to pointer
@AnT well, it was the other parts of the 6.7.6.2p1 that were needed to convince me :P
0

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).

1 Comment

I think that this answer misses the point. Compiler doesn't need to know the size due to array adjustment rules in N1570 $6.7.6.3.7. Question is, is there some other rule that has higher precedence, or is this simply a compiler bug?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.