Избавьтесь от предупреждения «Несовместимый указатель», вызванного typedef - PullRequest
0 голосов
/ 14 декабря 2018

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

У меня есть 2 дочерних структуры, давайте назовем их ChildA и ChildB и базовая структура Base,

// predefines.h
typedef struct sBase Base;
typedef struct sChildA ChildA;
typedef struct sChildB ChildB;

// base.h
typedef struct sBase {
    // Base fields
} Base;

// child_a.h
typedef struct sChildA {
    Base* base;
    // other things
} ChildA;

// child_b.h
typedef struct sChildB {
    Base* base;
    // other things
} ChildB;

Все должно быть хорошо, а?И это работает, за исключением того, что генерирует так много предупреждений по всему моему коду, что других предупреждений, я просто не могу заметить их в моей IDE, потому что я просто вижу столько желтого .

У меня много функций, таких как:

void do_something(Base* base) {
    // Code code code
}

do_something(instance_of_child_a); // Warning here

Есть ли способ порадовать компилятор, не отключая предупреждения этого типа?Большое спасибо.

edit: Вот предупреждение:

примечание: ожидается 'Base * {aka struct sBase *}', но аргумент имеет тип'ChildA * {aka struct sChildA }' void do_something (LitBase base);

1 Ответ

0 голосов
/ 14 декабря 2018

Вы получаете предупреждение, потому что ChildA* несовместимо с Base*.Это явно разные типы структур.А поскольку они несовместимы (в данном контексте это означает, что они идентичны), компилятор не может неявно преобразовывать их между собой.Это не раздражающее «ложное срабатывание», а нарушение языка Си, которое нельзя игнорировать.Многие компиляторы выдают ошибку и отказываются создавать двоичный файл.

Вы должны использовать явное приведение или просто передать член .base вручную.

Другая альтернатива явному приведению будетбыть макросом-обёрткой:

void base_do_something (Base* base);

#define do_something(x)                                       \
  base_do_something (                                         \
    _Generic( (x), ChildA*: &(x)->base, ChildB*: &(x)->base ) \
  )

Или эквивалентным:

#define do_something(x)                                       \
  base_do_something (                                         \
    _Generic( (x), ChildA*: (Base*)(x), ChildB*: (Base*)(x) ) \
  )

Как бы ни показывался подозрительный последний пример, он действительно действителен для C17 6.7.2.1 §15.И это не нарушает строгие псевдонимы, поскольку ChildA и т. Д. Является агрегатом, содержащим Base среди своих членов.Если вы не являетесь юристом по языкам, перейдите к 1-му примеру:)

...