Структура Typedef в C Vs С++

Это дает ошибку в С++, но не в C:

typedef struct nodes
{
    int data;
    struct node *next;
}node;

Он дает следующую ошибку в С++.

/home/DS cpp/linkedlist.cpp|10|error: conflicting declaration ‘typedef struct nodes node’|
/home/DS cpp/linkedlist.cpp|9|error: ‘struct node’ has a previous declaration as ‘struct node’|
||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

Чтобы он работал на С++, я должен изменить его на это:

typedef struct node
{
    int data;
    struct node *next;
}node;

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

Ответы

Ответ 1

Немного проанализируйте свой код:

typedef struct nodes
{
    int data;
    struct node *next;
}node;

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

Теперь в С++ объявление участника struct node *next автоматически пересылает объявление типа node. Тогда это конфликтует с вашим typedef target node: оно как будто вы пытаетесь присвоить два типа одинакового имени.

В C нет конфликта, потому что тип, называемый node, на самом деле можно назвать только struct node.

Второй фрагмент работал, потому что, поскольку во время разбора объявления участника struct node уже существует, новый тип не объявляется там forward & hellip; и поскольку все, что вы делаете, переименовывает его в один и тот же оператор typedef, С++ все равно, зная, что он все тот же тип (struct T is T; разница в синтаксисе, а не в название).

[C++11: 7.1.3/3]: В заданной неклассовой области спецификатор typedef может использоваться для переопределения имени любого типа, объявленного в этой области, для обозначения того типа, к которому он уже относится. [Пример:

typedef struct s { / ... / } s;
typedef int I;
typedef int I;
typedef I I;

-end пример]

[C++11: 7.1.3/6]: В заданной области спецификатор typedef не должен использоваться для переопределения имени любого типа, объявленного в этой области, для обозначения другого типа. [Пример:

class complex { / ... / };
typedef int complex; // error: redefinition

-end пример]

Конечно, в С++, все это спорный вопрос, и вы должны просто написать:

struct node
{
   int data;
   node* next;
};

Вам не нужно typedef -выбрать специфицированный тип-спецификатор struct.

Ответ 2

Приведенный пример C должен быть ошибкой. Вы используете имя тега (node), которое вы не определили с помощью struct node.

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

typedef struct node_t
{
    int data;
    struct node_t *next;
} node_t;

В C или С++ имена тегов имеют собственное пространство имен, поэтому нет проблем с использованием одного и того же имени для тега и имени typedef. В C это позволяет использовать node_t или struct node_t для обращения к этому типу структуры. С++ будет искать имена тегов для имени типа, если объявленное имя типа не существует, поэтому указанное выше двойное определение не требуется, но не больно.

В обоих языках явная версия struct node_t требуется в любой момент до того, как тип будет полностью определен, поэтому любая самореклама и любые прямые ссылки будут использовать версию struct. Я предпочитаю это в файлах заголовков, главным образом потому, что он уменьшает проблемы с порядком директив #include.

PS: Это работает на любом языке (см. ответ LRIO для указателей в С++ 11 Standard) и используется в достаточно двуязычных и даже чистых файлах заголовков С++, которые вряд ли скоро исчезнут), поэтому это очень просто подход, который работает только на любом языке.