Переопределение typedef
Я, возможно, делаю это неправильно, и это вопрос о том, почему он работает в одном компиляторе, а не в другом.
У меня есть большое приложение C, и я стараюсь следовать стилю не включая заголовочные файлы из других файлов заголовков. Вместо этого, используя форвардные объявления; таким образом, я пытаюсь сделать следующее.
// in A.h
typedef struct A_ A;
typedef struct B_ B;
struct A_ {
double a;
B *b;
};
// in B.h
typedef struct B_ B;
struct B_ {
int c;
};
// in C.h
typedef struct A_ A;
typedef struct B_ B;
void function_do_something(A*, B*);
// in C.c
#include "A.h"
#include "B.h"
#include "C.h"
void function_do_something(A* a, B* b) {
...
}
Эта парадигма компилируется и запускается в Ubuntu 11.10 gcc - но она дает компромиссные ошибки в OpenSUSE gcc, которые говорят "переопределить typedef".
Я делаю свое развитие в Ubunutu и поэтому не понял, что эта парадигма может быть неправильной. Разве это просто неправильно, и Ubuntu gcc слишком хорош?
Ответы
Ответ 1
Я был удивлен этим, потому что я уверен, что повторное использование одинакового typedef в той же области действия является законным в С++, но, по-видимому, оно не является законным в C.
Во-первых, имена typedef не имеют привязки:
ISO/IEC 9899: 1999 + TC3 6.2.6/6:
Следующие идентификаторы не имеют связи: идентификатор, объявленный как нечто иное, чем объект или функция [...]
и 6.7/3:
Если идентификатор не имеет привязки, должно быть не более одного объявления идентификатора (в спецификаторе декларатора или типа) с той же областью действия и в том же пространстве имен, кроме для тегов, указанных в 6.7.2.3.
Поэтому вам нужно убедиться, что каждое объявление typedef появляется только один раз в области файлов в каждой единицы перевода.
Ответ 2
Отсутствует одна часть идиомы. Передовые декларации не зависят от определений, поэтому они должны быть в отдельном файле заголовка.
// a_fwd.h
#ifndef A_FWD_H
#define A_FWD_H
typedef struct A_ A;
#endif
// a.h
#ifndef A_H
#define A_H
#include "a_fwd.h"
struct A_ {
};
#endif
Теперь всегда безопасно включать любые заголовки в любом порядке.
Нельзя иметь два определения чего-либо. Typedef - это определение, а не просто объявление, поэтому один компилятор был довольно слабым, чтобы позволить избыточность.
Ответ 3
Как раз в стиле, я бы поставил typedef после структуры. то есть:.
struct B_ {
int c;
};
typedef struct B_ B;
Таким образом вы говорите: "вот B_, и теперь я хочу называть его" B ". Может быть, иначе обманывать что-то в компиляторе.
Ответ 4
Компилятор ubuntu слишком мягкий; вы не можете напечатать одно и то же дважды. В том стиле, о котором вы говорите, упорядочение включений имеет важное значение и обычно упоминается как комментарий в файле заголовка или в документации. В этом случае у вас будет:
//A.h
typedef struct A A;
struct A {
double a;
B* b;
};
// B.h
typedef struct B B;
struct B {
int c;
};
// C.h
void function_do_something(A*, B*);
// C.c
#include "B.h"
#include "A.h"
#include "C.h"
void function_do_something(A* a, B* b){ ... }
Вы можете заметить, что это будет беспорядочно в случае циклических зависимостей.
Ответ 5
Вы переопределяете A и B, написав один и тот же оператор в нескольких файлах заголовков. Одним из решений было бы отказаться от typedef
от A и B от A.h и B.h и использовать ваш C.h как есть.
Ответ 6
Как уже указывали другие, вы не можете переопределять типы в C. Эта ошибка в основном указывает на то, что могут быть зацикленные включения или другие логические недостатки. Чтобы этого избежать, наилучшей практикой является блокировка файлов, например,
#ifndef __HEADER_H__
#define __HEADER_H__
// Your code goes here
#endif
Таким образом ненужные включения будут исключены этой блокировкой.
В вашем примере вам нужно включить B в и A в C. Включение B в C не будет иметь эффекта и удовлетворит компилятор
Ответ 7
Вы определяете несколько раз одно и то же.
Вы можете распространять его по нескольким файлам заголовков, просто нужно убедиться, что есть некоторый B, видимый до того, как определена структура _A.
Этот код работает:
#include <stdio.h>
typedef struct _B B;
typedef struct _A A;
struct _A {
double a;
B *b;
};
struct _B {
int c;
};
void function_do_something(A* a, B* b)
{
printf("a->a (%f) b->c (%d)\n", a->a, b->c);
}
int main()
{
A a;
B b;
a.a = 3.4;
b.c = 34;
function_do_something(&a, &b);
return 0;
}
Вывод:
> ./x
a->a (3.400000) b->c (34)
EDIT: обновлено для C
EDIT 2: распространение в несколько файлов заголовков
b.h:
#ifndef B_H
#define B_H
struct _B {
int c;
};
#endif
хиджры:
#ifndef A_H
#define A_H
typedef struct _B B;
struct _A {
double a;
B *b;
};
typedef struct _A A;
#endif
main.c:
#include <stdio.h>
#include "a.h"
#include "b.h"
void function_do_something(A* a, B* b)
{
printf("a->a (%f) b->c (%d)\n", a->a, b->c);
}
int main()
{
A a;
B b;
a.a = 3.4;
b.c = 34;
function_do_something(&a, &b);
return 0;
}