typedef struct vs struct definitions [дубликат]
этот вопрос уже есть ответ здесь:
Я новичок в программировании на 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две очень разные вещи.The
structключевое слово используется для определения или ссылки на тип структуры. Например, это:struct foo { int n; };создает новый тип под названием
struct foo. Имяfooэто tag; это имеет смысл только тогда, когда ему непосредственно предшествуетstructключевое слово, потому что теги и другие идентификаторы находятся в различных пространства имен. (Это похоже, но гораздо более ограничено, чем, концепция C++namespaces.)A
typedef, несмотря на название, не определяет нового типа; он просто создает новое имя для существующего типа. Например, дано:typedef int my_int;
my_intэто новое имя дляint;my_intиintare ровно один и тот же тип. Аналогично, учитываяstructопределение выше, вы можете написать:typedef struct foo foo;у типа уже есть имя,
struct foo. Элемент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. Элемент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иtypedefs это.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.The
structсам по себе является анонимным типом, поэтому у вас нет фактического имени для пересылки объявления.typedef struct{ int one; int two; } myStruct;прямое объявление, как это не будет работать:
struct myStruct; //forward declaration fails void blah(myStruct* pStruct); //error C2371: 'myStruct' : redefinition; different basic types
The
typedef, как и в других конструкциях, используется для присвоения типу данных нового имени. В этом случае это в основном делается для того, чтобы сделать код чище:struct myStruct blah;и
myStruct blah;
следующий код создает анонимную структуру с псевдонимом
myStruct:typedef struct{ int one; int two; } myStruct;вы не можете ссылаться на него без псевдонима, потому что вы не указываете идентификатор для структуры.
Я вижу некоторые разъяснения в порядке на этом. C и C++ не определяют типы по-разному. C++ изначально был не более чем дополнительным набором включений поверх C.
проблема, с которой сегодня сталкиваются практически все разработчики C/C++, заключается в том, что A) университеты больше не преподают основы, и b) люди не понимают разницы между определением и декларацией.
единственная причина, по которой такие объявления и определения существуют, заключается в том, что компоновщик можно рассчитать смещения адресов для полей в структуре. Вот почему большинству людей сходит с рук код, который на самом деле написан неправильно-потому что компилятор способен определить адресацию. Проблема возникает, когда кто-то пытается сделать что-то заранее, например очередь, или связанный список, или piggying-резервное копирование структуры O/S.
декларация начинается с ключевого слова struct', определение начинается с ключевого слова typedef'.
кроме того, структура имеет метку прямого объявления и a определенная метка. Большинство людей этого не знают и используют метку прямого объявления в качестве метки определения.
неправильно:
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;это сохранить некоторые набрав, и может быть более читаемым, но это дело вкуса
Comments