ошибка о массиве структуры C в формальном параметре - PullRequest
0 голосов
/ 24 мая 2018

У меня есть следующий код:

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 голосов
/ 24 мая 2018

С язык безоговорочно требует, чтобы тип элемента массива в все объявления массива были завершены.Период.

6.7.6.2 Деклараторы массива
Ограничения
1 [...] Тип элемента не долженбыть неполным или типом функции.[...]

Не сделано никаких исключений для объявлений массива, используемых в списках параметров функции.Это отличается от C ++ - последний отбрасывает это требование полноты для списков параметров функции

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

Учитывая, что в объявлении списка параметров тип T [] позднее в любом случае настраивается на тип T *, это требование может выглядеть так:быть чрезмерным(И именно поэтому C ++ смягчил это.) Тем не менее, это ограничение присутствует в языке Си.Это лишь одна из особенностей языка C.

Как вы уже знаете, вы можете явно переключиться на эквивалентную

void paiming1(struct student_info *student); 

форму, чтобы обойти эту проблему.

0 голосов
/ 24 мая 2018

Внимательное прочтение стандарта проясняет, что в C99 и C11 декларация считается нарушением ограничения. C11 6.7.2.6 Объявления массива p1

  1. В дополнение к необязательным квалификаторам типов и ключевому слову static, [ и ] могут разделять выражение или *.Если они разграничивают выражение (которое определяет размер массива), выражение должно иметь целочисленный тип.Если выражение является константным выражением, оно должно иметь значение больше нуля. Тип элемента не должен быть неполным или типом функции .Необязательные квалификаторы типов и ключевое слово static должны появляться только в объявлении параметра функции с типом массива, а затем только при выводе самого внешнего типа массива.

Поскольку он содержит ссылки на *, который действителен только в объявлениях функций, которые не являются определениями , и нигде больше, ограничения в целом должны бытьпринимается как применение к параметрам.


Для C90 дело обстоит сложнее.Это на самом деле обсуждается в C90 Отчете о дефектах 47 от 10 декабря 1992 г. .

2 из 6 приведенных объявлений:

/* 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.

0 голосов
/ 24 мая 2018

Компилятор ничего не знает о размере 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[]); 

Когда вы объявляете его как указатель с помощью *, компилятор знает размер аргумента (его адрес).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...