typedef struct vs struct definitions [дубликат]



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



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



struct myStruct{
int one;
int two;
};


и



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

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++namespace s.)

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

typedef int my_int;

my_int это новое имя для int;my_int и int are ровно один и тот же тип. Аналогично, учитывая 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

    Ничего не найдено.