Почему `typedef struct xx` разрешена? - PullRequest
0 голосов
/ 10 июня 2019

Я читал книгу Современный C и был удивлен, обнаружив, что следующий код работает

typedef struct point point;
struct point {
    int x;
    int y;
};

int main() {
   point p = { .x = 1, .y = 2 };
}

Однако в книге не говорится подробно об этом.Как это работает?Почему point в main() относится к typedef, поскольку struct point определяется после этого?

Ответы [ 4 ]

6 голосов
/ 10 июня 2019

Строка typedef struct point point; делает две вещи:

  • Создает прямое объявление из struct point
  • Создает псевдоним типа для struct point named point.

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

typedef struct x X;

typedef struct y {
    int a;
    X *x;
} Y;

 struct x {
     int b;
     Y *y;
 };
2 голосов
/ 11 июня 2019

Это работает, потому что C имеет несколько пространств имен :

  • меток (с неоднозначностью goto или конечных :);
  • имен тегов дляstruct, enum и union (устраняется неоднозначность по ключевым словам struct, union или enum):
  • имена для struct и union членов (исключаются поведущий . или ->, каждый тип struct или union действует как свое собственное пространство имен, поэтому разные типы struct и union могут использовать одни и те же имена членов);
  • allдругие идентификаторы (имена переменных и функций, имена типов, константы перечисления и т. д.).

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

struct x { int x; }; // tag name, member name

void foo( struct x x ) // tag name, all other identifiers
{
  if ( x.x ) // all other identifiers, member name
    goto x;  // label name

  // do something here

  x: printf( "At label x\n" ); // label name
}
2 голосов
/ 10 июня 2019

Вы можете использовать struct foo во многих местах до определения struct foo { ... }.Это называется «неполным типом».

Это полезно, поскольку позволяет определять абстрактные типы:

foo_header.h

struct foo;  // abstract
struct foo *foo_create(void);
void do_stuff_with(struct foo *);
void foo_destroy(struct foo *);

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

Она также используется в рекурсивных типах:

struct node {
    int data;
    struct node *next;  // struct node isn't defined yet!
};
// here the definition of struct node is complete

C поддерживает это, потому что это легко реализовать: чтобы скомпилировать код, который использует struct foo *, компилятору нужно только знать, насколько велик указатель.Он не заботится о членах структуры.

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

1 голос
/ 10 июня 2019

Этот пример взят прямо из стандарта C, раздел 6.7.2.3:

В следующей альтернативной формулировке используется механизм typedef:

typedef struct tnode TNODE;
struct tnode {
 int count;
 TNODE *left, *right;
};
TNODE s, *sp;

Что он делаетforward объявляет struct, а затем создает для нее псевдоним типа.

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