typedef struct vs struct определения [дубликат]

этот вопрос уже есть ответ здесь:

Я новичок в программировании на C, но мне было интересно, в чем разница между использованием typedef при определении структуры и не использованием typedef. Мне кажется, что на самом деле нет никакой разницы. сделайте то же самое.

struct myStruct{
    int one;
    int two;
};

и

typedef struct{
    int one;
    int two;
}myStruct;

12 ответов


общая идиома использует оба:

typedef struct X { 
    int x; 
} X;

это разные определения. Чтобы сделать обсуждение более ясным, я разделю предложение:

struct S { 
    int x; 
};

typedef struct S S;

в первой строке вы определяете идентификатор S в пространстве имен структуры (не в смысле C++). Вы можете использовать его и определить переменные или аргументы функции нового определенного типа, определив тип аргумента как struct S:

void f( struct S argument ); // struct is required here

вторая строка добавляет тип псевдоним S в глобальном пространстве имен и, таким образом, позволяет просто написать:

void f( S argument ); // struct keyword no longer needed

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

чтобы сделать разницу более ясной:

typedef struct S { 
    int x; 
} T;

void S() { } // correct

//void T() {} // error: symbol T already defined as an alias to 'struct S'

вы можете определить функцию с тем же именем структуры, что и идентификаторы хранятся в разных пространствах, но вы не можете определить функцию с тем же именем, что и typedef как эти идентификаторы наехать.

в C++ он немного отличается, так как правила поиска символа изменились тонко. C++ по-прежнему сохраняет два разных пространства идентификаторов, но в отличие от C, когда вы определяете символ только в пространстве идентификаторов классов, вам не требуется предоставлять ключевое слово struct/class:

 // C++
struct S { 
    int x; 
}; // S defined as a class

void f( S a ); // correct: struct is optional

какие изменения в поиске правила, а не где идентификаторы определены. Компилятор будет искать глобальную таблицу идентификаторов и после S не найден он будет искать S внутри идентификаторов классов.

код, представленный ранее, ведет себя таким же образом:

typedef struct S { 
    int x; 
} T;

void S() {} // correct [*]

//void T() {} // error: symbol T already defined as an alias to 'struct S'

после определения S функция во второй строке структура S не может быть автоматически разрешена компилятором, и для создания объекта или определения аргумента этого типа вы должны упасть вернемся к включению struct ключевые слова:

// previous code here...
int main() {
    S(); 
    struct S s;
}

struct и typedef это две совершенно разные вещи.

на struct ключевое слово используется для определения или ссылки на тип структуры. Например, это:

struct foo {
    int n;
};

создает новый тип struct foo. Имя foo это tag; это имеет смысл только тогда, когда ему непосредственно предшествует struct ключевое слово, потому что теги и другие идентификаторы находятся в distinct пространства имен. (Это похоже на, но гораздо более ограничено, чем, концепция C++ от namespaces.)

A typedef, несмотря на название, не определяет нового типа; он просто создает новое имя для существующего типа. Например, дано:

typedef int my_int;

my_int это новое имя для int; my_int и int are ровно один и тот же тип. Аналогично, учитывая struct определение выше, вы можете написать:

typedef struct foo foo;

у типа уже есть имя,struct foo. The typedef объявление дает тот же тип новое имя, foo.

синтаксис позволяет комбинировать struct и typedef в одном объявлении:

typedef struct bar {
    int n;
} bar;

это распространенная идиома. Теперь вы можете ссылаться на этот тип структуры либо как struct bar или bar.

обратите внимание, что имя typedef не становится видимым до конца объявления. Если структура содержит указатель на себя, вы должны использовать struct версия для ссылки на него:

typedef struct node {
    int data;
    struct node *next; /* can't use just "node *next" here */
} node;

некоторые программисты будут использовать различные идентификаторы для тега struct и для имени typedef. На мой взгляд, для этого нет веской причины; использование одного и того же имени совершенно законно и дает понять, что они одного типа. Если вы должны использовать разные идентификаторы, по крайней мере, используйте согласованное соглашение:

typedef struct node_s {
    /* ... */
} node;

(лично я предпочитаю не указывать typedef и относятся к типу как struct bar. The typedef сохранить немного печатаю, но он скрывает тот факт, что это тип структуры. Если вы хотите, чтобы тип был непрозрачным, это может быть хорошо. Если клиентский код будет ссылаться на член n по имени, тогда это не непрозрачно; это явно структура, и, на мой взгляд, имеет смысл ссылаться на нее как на структуру. Но многие умные программисты со мной не согласны. Будьте готовы читать и понимать код, написанный в любом случае.)

(C++ имеет разные правила. Дано объявление struct blah, вы можете ссылаться на тип как раз blah, даже без синонима. Использование typedef может сделать ваш C-код немного более похожим на C++-если вы считаете, что это хорошо.)


еще одно отличие Не указано, что предоставление структуры имя (т. е. struct myStruct) также позволяет предоставлять прямые объявления структуры. Поэтому в каком-то другом файле вы можете написать:

struct myStruct;
void doit(struct myStruct *ptr);

без необходимости иметь доступ к определению. Я рекомендую вам объединить два примера:

typedef struct myStruct{
    int one;
    int two;
} myStruct;

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


в C (не c++) вы должны объявить переменные структуры, такие как:

struct myStruct myVariable;

для того, чтобы иметь возможность использовать вы можете typedef структура:

typedef struct myStruct someStruct;
someStruct myVariable;

вы можете комбинировать struct определение и typedefs это в одном заявлении, которое объявляет анонимный struct и typedefС его.

typedef struct { ... } myStruct;

если вы используете struct без typedef, вам всегда придется писать

struct mystruct myvar;

это незаконно писать

mystruct myvar;

если вы используете typedef не требуется struct префикс больше.


в C ключевые слова спецификатора типов структур, союзов и перечислений обязательны, т. е. вы всегда должны префиксировать имя типа (его tag) С struct, union или enum при обращении к типу.

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

поэтому рекомендуется (см., например,ядра Linux руководство по стилю кода, Глава 5) делать это только тогда, когда вы на самом деле хочу чтобы скрыть эту информацию, а не просто сохранить несколько нажатий клавиш.

пример, когда вы должны использовать typedef будет непрозрачным типом, который используется только с соответствующими функциями/макросами доступа.


разница приходит, когда вы используете struct.

первый способ, который вы должны сделать:

struct myStruct aName;

второй способ позволяет удалить ключевое слово struct.

myStruct aName;

вы не можете использовать упреждающее объявление с typedef struct.

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

typedef struct{
    int one;
    int two;
} myStruct;

такое прямое объявление не будет работать:

struct myStruct; //forward declaration fails

void blah(myStruct* pStruct);

//error C2371: 'myStruct' : redefinition; different basic types

на typedef, как и в других конструкциях, используется для присвоения типу данных нового имени. В этом случае это в основном делается для того, чтобы сделать код чище:

struct myStruct blah;

и

myStruct blah;

следующий код создает анонимную структуру с псевдонимом myStruct:

typedef struct{
    int one;
    int two;
} myStruct;

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


Я вижу, что некоторые разъяснения по этому поводу. C и C++ не определяют типы по-разному. C++ изначально был не более чем дополнительным набором includes поверх C.

проблема, которую сегодня имеют практически все разработчики C / C++, заключается в том, что A) университеты больше не преподают основы, и b) люди не понимают разницы между определением и декларацией.

единственная причина, по которой такие объявления и определения существуют, - это то, что компоновщик можно рассчитать смещения адресов для полей в структуре. Вот почему большинству людей сходит с рук код, который на самом деле написан неправильно-потому что компилятор может определить адресацию. Проблема возникает, когда кто-то пытается сделать что-то заранее, например очередь, или связанный список, или piggying-резервное копирование структуры O/S.

объявление начинается с 'struct', определение начинается с'typedef'.

кроме того, структура имеет прямого отношения декларацию, и определенная метка. Большинство людей этого не знают и используют метку прямого объявления в качестве метки определения.

неправильно:

struct myStruct
   {
   int field_1;
   ...
   };

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

люди, которые используют эту форму декларации, должны всегда ставить "структурировать" практически каждую ссылку на него-потому что это не официальный новый тип.

любая структура, которая не ссылается на себя, должна быть объявлена и определена таким образом:
typedef struct
   {
   field_1;
   ...
   }myStruct;

теперь это фактический тип, и при использовании вы можете использовать в качестве "myStruct" без необходимости добавлять его со словом "struct".

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

typedef struct
   {
   field_1;
   ...
   }myStruct,*myStructP;

теперь у вас есть указатель переменной структурой, настраиваемые на него.

ПЕРЕДНЕЕ ОБЪЯВЛЕНИЕ--

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

typedef struct myStructElement
   {
   myStructElement*  nextSE;
   field_1;
   ...
   }myStruct;

теперь компилятор знает, что, хотя он еще не знает, что такое весь тип, он все еще может ссылаться на него, используя прямую ссылку.

пожалуйста, объявите и typedef ваши структуры правильно. На самом деле есть причина.


в последнем примере вы опускаете ключевое слово struct при использовании структуры. Поэтому везде в вашем коде вы можете написать:

myStruct a;

вместо

struct myStruct a;

это сохранить некоторые набрав, и может быть более читаемым, но это дело вкуса