Структура 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) и используется в достаточно двуязычных и даже чистых файлах заголовков С++, которые вряд ли скоро исчезнут), поэтому это очень просто подход, который работает только на любом языке.