关于形式参数中的C struct数组的错误

时间:2018-05-24 07:29:57

标签: c function-declaration incomplete-type

我有以下代码:

struct student_info;
void paiming1(struct student_info student[]); 
struct student_info  
{
    int num; 
    char name[6]; 
};

IDE出错

error: array type has incomplete element type ‘struct student_info’
 void paiming1(struct student_info student[]);

但如果我使用void paiming1(struct student_info *student);,它就可以了。这是为什么?我正在使用GCC。

3 个答案:

答案 0 :(得分:7)

С语言无条件地要求所有数组声明中的数组元素类型完整。期。

  

6.7.6.2数组声明符
  的约束
   1 [...]元素类型不应是不完整或函数   类型。 [...]

函数参数列表中使用的数组声明没有异常。这与C ++不同 - 后者降低了函数参数列表的完整性要求

struct S;
void foo(struct S[]); // OK in C++, invalid in C

考虑到参数列表声明类型T []后来被调整为T *类型,此要求似乎过多。 (这就是C ++放宽它的原因。)然而,这种限制存在于C语言中。这只是C语言的一个怪癖。

如您所知,您可以明确切换到等效的

void paiming1(struct student_info *student); 

形成解决问题的方法。

答案 1 :(得分:6)

仔细阅读标准清楚地表明,在C99和C11中,声明应该是违反约束的。 C11 6.7.2.6 Array declarations p1

  
      
  1. 除了可选的类型限定符和关键字static之外,[]可以分隔表达式或*。如果它们分隔表达式(指定数组的大小),则表达式应具有整数类型。如果表达式是常量表达式,则其值应大于零。 元素类型不应为不完整或函数类型。可选的类型限定符和关键字static只出现在具有数组类型的函数参数的声明中,然后仅出现在最外层的数组类型派生中。
  2.   

由于这包含仅在非定义的函数声明中有效*的引用,以及其他地方,因此整个约束需要被视为应用于参数。

对于C90来说,情况更复杂。这实际上是在1992年12月10日的 C90 Defect Report 47中讨论的

给出的6个声明中有2个

/* 1. */ struct S;
/* 3. */ struct S *g(struct S a[]) { return a; }

并且缺陷报告询问这些是否严格符合要求。必须注意的是,与问题不同的是,这些是定义的一部分原型,而不仅仅是声明。

然而,标准委员会回应说

  

struct S是不完整的类型(子条款6.5.2.3,第62页,第25-28行)。此外,未知大小的数组是不完整类型(子条款6.5.4.2,第67页,第9-10行)。 因此,上述任何一个的数组都不严格符合(第6.1.2.5节,第23页,第23-24行)。这使得声明 3 ,4和6不严格符合。 (但是实施可以使它正确。)

     

另外,数组参数调整为指针类型(子条款6.7.1,第82页,第23-24行)。 但是,没有任何迹象表明通过此规则可以神奇地将非严格一致的数组类型转换为严格符合指针的参数。

     

有问题的类型可以用两种不同的方式解释。 (数组到指针的转换可能会尽快发生或尽可能晚。)因此,使用此类表单的程序具有未定义的行为。

(强调我的)

由于 1992 以来没有书面澄清,我们必须同意行为未定义,因此 C标准没有要求,并且编译器成功编译这个仍然符合C90。

委员会还指出C90中存在无约束违规,因此符合C90的编译器无需输出任何诊断信息。

我编辑了答案;我之前声称这将适用于C99和C11,但文本在C99中如上所述进行了更改,因此这是C99,C11中的约束违规。

答案 2 :(得分:0)

编译器在声明struct student_info的大小之前并不知道。这应该有效:

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[]); 

当您使用*将其声明为指针时,编译器知道参数的大小(它的地址)。