Как объявить структуру, которая не будет генерировать предупреждение? - PullRequest
0 голосов
/ 25 февраля 2012

Вопрос кажется классическим, но я не нашел ответа:

У меня есть два типа структуры, написанные на C ------ тип структуры A и тип структуры B, иB использовать A, в то время как A использовать B одновременно.

В ах:

#include "b.h"
struct B;
typedef struct A {
    void (*func)(struct B* b);
}A;

В чч:

#include "a.h"
typedef struct B {
    A a;
}B;

, хотя это будет работать, оно имеетследствие --- при использовании функции fun "func", если я передам переменную, объявленную в виде:

B* someb;

not:

struct B* someb;

при компиляции появится предупреждениеговорят несовместимый тип указателя.Это нормально?можно ли избежать этого предупреждения?

Ответы [ 4 ]

2 голосов
/ 25 февраля 2012

Зависимости циклического включения никогда не являются хорошей идеей.

Самый простой способ - иметь предварительные объявления для тега struct и typedef в "ах"

typedef struct A A;
typedef struct B B;
2 голосов
/ 25 февраля 2012

Из заголовочного файла a.h просто удалите строку #include "b.h". Предварительная декларация struct B; - это все, что вам нужно.

Это изменение исправит циклическую зависимость include и сделает любой код, использующий эти заголовки, более разумным.

Затем, где бы вы ни хотели использовать структуру B, просто включите b.h и используйте ее с ключевым словом struct или без него.

Код для иллюстрации: заголовочный файл a.h:

/* a.h */
struct B;

typedef struct A {
    void (*func)(struct B* b);
} A;

Заголовочный файл b.h:

/* b.h */
#include "a.h"

typedef struct B {
    A a;
} B;

Файл, который использует следующие заголовочные файлы:

/* some_file.c */
#include "b.h"

void fun() {
    B someb;
    someb.a.func(&someb);
}

void fun2() {
    struct B someb;
    someb.a.func(&someb);
}

Оба fun и fun2 в порядке (с точки зрения компилятора - func не инициализирован, поэтому вызов его вызовет проблему во время выполнения).

0 голосов
/ 25 февраля 2012

struct whatever { /* ... */ }; определяет новый тип.
Это имя нового типа struct whatever.

Вы можете определить другое имя для типа с помощью typedef либо втот же оператор, который определяет тип

typedef struct whatever { /* ... */ } newtypename;

или другой оператор

struct whatever { /* ... */ };
typedef struct whatever newtypename;

Вы можете даже определить тип struct без имени и получить для него новое имя

typedef struct { /* ... */ } newtypenameforstructwithnotag;
0 голосов
/ 25 февраля 2012

Функция func, как вы объявили, она получает в качестве входных данных указатель на объект struct B, поэтому при вызове функции вы должны сделать так:

B* somePointer; //because of your typedef you can omit struct 
func(somePointer);

Я пропустил часть выделенияпамять, которой вы также должны управлять ...

Как показывает вопрос SO Предупреждение компилятора: тип указателя, несовместимый с инициализацией , вы должны передать указатель на функцию, чтобы сделать изменения видимыми в объекте,в противном случае вы просто передаете копию структуры B, и каждое внесенное вами изменение будет действовать только в области действия функций.

Я полагаю, что это является причиной предупреждения.

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