Подтвердить что ты не робот

В чем смысл `struct X typedef` и` typedef struct X`?

У меня есть следующий (рабочий) код в существующей базе кода, используемый в include файле, который используется совместно с C и С++, компиляция на MSVC (2010) и Windows DDK:

struct X {
    USHORT x;
} typedef X, *PX;

и

enum MY_ENUM {
    enum_item_1,
    enum_item_2 
} typedef MY_ENUM;

Насколько я знаю, правильное определение должно выглядеть так:

typedef struct {
    USHORT x;
} X, *PX;

Есть ли какая-либо цель иметь форму ниже? Я что-то пропустил?

4b9b3361

Ответ 1

Тот факт, что оба typedef <type> <alias> и <type> typedef <alias> действительны, просто исходит из определения грамматики языка.

typedef классифицируется как спецификатор класса хранения (точно так же, как static, auto), а сам тип известен как спецификатор типа. Из определений синтаксиса в разделе 6.7 стандарта вы увидите, что они могут быть взаимозаменяемы:

declaration:
    declaration-specifiers init-declarator-list ;

declaration-specifiers:
    storage-class-specifier declaration-specifiers
    type-specifier declaration-specifiers
    type-qualifier declaration-specifiers
    function-specifier declaration-specifiers

init-declarator-list:
    init-declarator
    init-declarator-list , init-declarator

init-declarator:
    declarator
    declarator = initializer

(Обратите внимание, что это справедливо и для структур и для неструктур, что означает, что double typedef trouble; также действителен.)

Ответ 2

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

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

(C11, 6.11.5p1) "Размещение спецификатора класса хранения, отличное от начала спецификаторов декларации в объявлении, является устаревшей функцией.

Ответ 3

Оба имеют одинаковое значение. Обе эти формы действительны:

typedef <existing_type> <new_type>
<existing_type> typedef <new_type>   

Вы можете typedef структуру выше в любом случае:

struct X {
    USHORT x;
}typedef X, *PX;     // <existing_type> typedef <new_type> 

или

typedef struct {
    USHORT x;
} X, *PX;            // typedef <existing_type> <new_type>

Ответ 4

Вам действительно разрешено указывать все спецификаторы декларации в любом порядке! Позиции любых указателей * и фактического декларатора (имя переменной или нового типа) имеют значение, но все, что typedef int unsigned const static и т.д., Могут быть в любом порядке.

Если вы посмотрите на официальную грамматику C, она просто скажет:

declaration:
    declaration-specifiers init-declarator-list ;

declaration-specifiers - все спецификаторы класса хранения (typedef, extern и т.д.), спецификаторы типов (фактический тип, например int или struct X), классификаторы типов (const и volatile) и несколько других менее распространенных. Их порядок не важен. Вторая часть - это init-declarator-list, а это имя переменной или нового типа (в случае typedef), любые символы *, инициализация переменной (int x = 3) и многое другое. Порядок вещей в части декларатора важен, но не порядок в спецификаторах объявлений.

Ответ 5

Отказ от ответственности: это не технический, а практический ответ. См. Другие ответы по техническим вопросам. Этот ответ гласит упрямый и субъективный, но, пожалуйста, несите меня, пока я пытаюсь объяснить большую картину.

struct - странный зверь, потому что материал, который вы помещаете между закрывающей скобкой } и точкой с запятой ;, относится к содержимому внутри или перед этими скобками. Я знаю, почему это так, и грамматически это имеет смысл, но лично я считаю это очень противоречивым, поскольку фигурные скобки обычно означают область:

Контринтуитивные примеры:

// declares a variable named `foo` of unnamed struct type.
struct {
    int x, y;
} foo;

foo.x = 1;


// declares a type named `Foo` of unnamed struct type
struct {
    int x, y;
} typedef Foo;

Foo foo2;
foo2.x = 2;


// declares a type named `Baz` of the struct named `Bar`
struct Bar {
    int x, y;
} typedef Baz;

// note the 'struct' keyword to actually use the type 'Bar'
struct Bar bar;
bar.x = 3;
Baz baz;
baz.x = 4;

Есть так много тонких вещей, которые могут пойти не так с плотным синтаксисом struct и typedef, если они используются так. Как показано ниже, очень легко объявить переменную вместо типа случайно. Компилятор имеет ограниченную помощь, потому что почти все комбинации являются грамматически правильными. Они просто не обязательно означают, что вы пытаетесь выразить. Это яма отчаяния.

Неверные примеры:

// mixed up variable and type declaration
struct foo {
    int x, y;
} Foo;

// declares a type 'foo' instead of a variable
typedef struct Foo {
    int x, y;
} foo;

// useless typedef but compiles fine
typedef struct Foo {
    int x, y;
};

// compiler error
typedef Foo struct {
    int x, y;
};

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

Интуитивные примеры:

// declares a struct named 'TVector2'
struct TVector2 {
    float x, y;
};

// declares a type named 'Vector2' to get rid of the 'struct' keyword
// note that I really never use 'TVector2' afterwards
typedef struct TVector2 Vector2;

Vector2 v, w;
v.x = 0;
v.y = 1;