массивы еще не определенных типов (неполный тип элемента) - PullRequest
2 голосов
/ 21 февраля 2011

Можно ли создать массив объявленных, но не определенных типов? Вот что я хотел бы сделать:

typedef struct _indiv indiv;
typedef indiv pop[];

и пусть кто-то другой решит, что на самом деле являются членами индивидуума, определив struct _indiv в другом файле .c или .h (а затем связав все вместе).

(В семантике индивид - это индивидуум, а поп - это популяция индивидов.)

Но компилятор жалуется:

error: array type has incomplete element type

Я мог бы заменить второй typedef на

typedef indiv * pop;

И использовать pop как массив, получая доступ к таким элементам, как p[i] (с p типа pop), но если я это сделаю, компилятор пожалуется, что

error: invalid use of undefined type ‘struct _indiv’
error: dereferencing pointer to incomplete type

Я полагаю, поскольку typedef struct _indiv indiv является только объявлением, компилятор не знает во время компиляции (до связывания), сколько места требуется структуре и что ей не нравится, что запрещает делать то, что я пробовать. Но я хотел бы знать, почему и есть ли способ добиться того, чего я хочу.

Спасибо

Ответы [ 3 ]

2 голосов
/ 21 февраля 2011

Если вы хотите, чтобы этот исходный файл управлял элементами типа indiv, то у вас есть 2 варианта.

1) Объявите структуру, но не определяйте ее. Используйте только указатели на структуру. Никогда не разыскивай их:

 struct _indiv;
 typedef struct _indiv indiv; 
 typedef indiv * pop;
 //sizeof(_indiv) is not known, how many bytes should we allocate?
 pop p = malloc(N*unknownSize); 
 //this line will fail because it does not know how many bits to copy.
 p[0] = getIndiv();

2) определить полную структуру:

 struct _indiv
 {
    int id;
    char* name; 
    /*...*/
 };
 typedef struct _indiv indiv; 
 typedef indiv * pop;
 pop p = malloc(N*sizeof(indiv));
 //Now this line can work.
 p[0] = getIndiv();

Предложение по определению фиктивного индивида плохое:

 --- file1.c

 struct _indiv
 {
    char dummy;
 };
 typedef struct _indiv indiv; 
 typedef indiv * pop;
 pop p = malloc(N*sizeof(indiv));  //this will allocate N bytes.
 //This will generate code that copies one byte of data.
 p[0] = getIndiv();

 ---realIndiv.c

 typedef struct _indiv
 {
    int id;
    char* name; 
    /*...*/
 } indiv;
 indiv getIndiv();
 {
    indiv i = /* whatever */;
    return i;    //this will return 8+ bytes.
 }   

Когда вы сделаете это, первый файл будет манипулировать элементом другого размера, чем «реальная» индивидуальная структура, и вы обязательно получите неожиданное поведение.

1 голос
/ 22 февраля 2011

Вы правы в том, что компилятор не знает размер неполных типов (в вашем примере struct _indiv является неполным типом), поэтому вы не можете объявить переменную такого типа. Это включает в себя создание массива таких типов.

Однако это не имеет большого значения, потому что, если у вас нет полного определения типа, вы все равно не сможете получить доступ к его членам: если вы пишете p[i].foo, как вы узнаете, что тип на самом деле имеет член с именем foo, и если это так, то какой это тип?

Если вы хотите, чтобы члены типа struct были определены в другом файле .c (он известен как "непрозрачный тип"), тогда вам нужно только создавать и обрабатывать указатели на структуру. Ваш другой .c должен содержать весь код, который фактически обращается к самому struct. Файл с неполным типом будет содержать код, подобный следующему:

indiv *i1, *i2;

i1 = new_individual("foo"); /* Create an individual */
i2 = new_individual("bar");

print_individual(i1);

... и исходный файл с полным определением struct будет содержать реализацию new_individual(), print_individual() и т. Д.

В соответствии с этой схемой самый простой способ справиться с населением - создать массив указателей на indiv структур.

0 голосов
/ 21 февраля 2011

Вы можете определить массив указателей только для неопределенного типа, потому что вы не знаете размер этого типа.

Обратите внимание, что в языке Си вы можете по-разному определять одну и ту же структуру во многих местах. Вы можете использовать эту технику: просто определите свою структуру в любом случае, затем вы можете свободно определять и использовать указатели на этот тип. А затем определите реальную структуру с тем же именем где-нибудь еще. Также вы получаете тот же эффект, когда просто используете массивы void*.

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