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

pur*_*Zer 9 c function-declaration incomplete-type

我有以下代码:

struct student_info;
void paiming1(struct student_info student[]); 
struct student_info  
{
    int num; 
    char name[6]; 
};
Run Code Online (Sandbox Code Playgroud)

IDE出错

error: array type has incomplete element type ‘struct student_info’
 void paiming1(struct student_info student[]);
Run Code Online (Sandbox Code Playgroud)

但是,如果我使用void paiming1(struct student_info *student);它工作正常.这是为什么?我正在使用GCC.

AnT*_*AnT 7

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

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

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

struct S;
void foo(struct S[]); // OK in C++, invalid in C
Run Code Online (Sandbox Code Playgroud)

考虑到参数列表声明类型T []后来被调整为T *无论如何都要调整,这个要求可能看起来过多了.(这就是C++放宽它的原因.)然而,这种限制存在于C语言中.这只是C语言的一个怪癖.

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

void paiming1(struct student_info *student); 
Run Code Online (Sandbox Code Playgroud)

形成解决问题的方法.


Ant*_*ala 6

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

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

由于这包含对仅在非定义的函数声明中*有效的引用,而在其他任何地方都没有,因此整个约束需要被视为应用于参数.


对于C90来说,情况更复杂.这在1992年12月10日的C90 缺陷报告47中进行了实际讨论.

给出了6个声明中的2个

/* 1. */ struct S;
/* 3. */ struct S *g(struct S a[]) { return a; }
Run Code Online (Sandbox Code Playgroud)

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

然而,标准委员会回应说

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中的约束违规.


aic*_*ell 0

在声明 struct Student_info 之前,编译器不知道有关它的大小的任何信息。这应该有效:

\n\n
struct student_info                                                              \n{                                                                                \n    int num; //\xe5\xad\xa6\xe5\x8f\xb7                                                              \n    char name[6]; //\xe5\xa7\x93\xe5\x90\x8d                                                         \n    char sex[5]; //\xe6\x80\xa7\xe5\x88\xab                                                          \n    char adress[20]; //\xe5\xae\xb6\xe5\xba\xad\xe4\xbd\x8f\xe5\x9d\x80                                                  \n    char tel[11]; //\xe7\x94\xb5\xe8\xaf\x9d                                                         \n    int chinese,math,english,huping,pingde,jiaoping,paiming1,paiming2;           \n    double ave,zhongping;                                                        \n};                                                                               \n\nvoid paiming1(struct student_info student[]);                                    \nvoid paiming2(struct student_info student[]); \n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n

  • 我认为这个答案没有抓住要点。由于 N1570 $6.7.6.3.7 中的数组调整规则,编译器不需要知道大小。问题是,是否有其他一些具有更高优先级的规则,或者这只是一个编译器错误? (3认同)