C: прямое объявление определения типа, которое будет определено позже для использования при объявлении функции сейчас

#c #typedef #forward-declaration

#c #typedef #прямое объявление

Вопрос:

Итак .. У меня происходит что-то вроде курицы и яйца.

Я получил Controller_setup.h и Equipment_setup.h, которые используют определения типа, определенные в другом. Я мог бы много написать здесь об обосновании того, почему это так, но воздержусь от этого, если кто-то действительно не захочет знать (хотя в основном это была попытка заставить код в Equipment_setup.c / h работать с разными системами контроллеров, просто имея другой Controller_setup.h).

На предыдущем контроллере и компиляторе (контроллер использовал процессор ARM, а мы использовали компилятор IAR и IDE) мы разработали код, в котором я смог переадресовать объявление / переопределение определений типа, и это сработало бы. Это дало бы нам много предупреждений, но это скомпилировалось бы и сработало.

Теперь, когда мы фактически пытаемся перенести на другой контроллер, используя другую IDE и компилятор (контроллер использует процессор TriCore, и мы используем IDE Code::blocks с компилятором GNU GCC для TriCore V3.4.6), он теперь выдает ошибки и не позволяет коду компилироваться.

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

Поскольку оно работало на одном компиляторе (по общему признанию, с предупреждениями) Я надеюсь, что есть какой-то способ заставить его работать сейчас. Я не думаю, что это так просто, как использовать другой синтаксис, не так ли? Возможно ли объявить typedef вместо его переопределения?

На самом деле я только что погуглил этот точный вопрос, и, следуя этому пути, я, кажется, теперь понимаю, что то, что я хочу сделать, разрешено в C11, но не в предыдущих стандартах C. И, насколько я могу судить, компилятор Tricore не поддерживает C11, так что, вероятно, именно поэтому он работал раньше, но не сейчас.

Но если бы кто-нибудь мог помочь проверить это понимание, это было бы оценено.

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

Ниже приведена упрощенная версия того, что сработало, но не сейчас. Я пропустил части, где Controller_setup.h ссылается на Equipment_setup.h . Когда проект построен, Equipment_setup.h считывается первым, поэтому я получаю ошибку при переопределении в Controller_setup.h считывается.

Сообщение об ошибке:

  • ошибка: [12993] переопределение typedef ‘IO_link_t’
  • ошибка: [13256] предыдущее объявление ‘IO_link_t’ было здесь

Equipment_setup.h

 //The functions declared here are used by other .c files which
//determine how the equipment is to operate

typedef enum IO_devices_t IO_devices_t;
typedef struct IO_link_t IO_link_t;

//Declare function for checking status of a given IO device
uint8_t check_IO_device_status(IO_device_t device);

//Declare function for calibrating an input
uint8_t calibrate_input(IO_link_t*  input);
  

Controller_setup.h

 typedef enum IO_devices_t{
  MAIN_CONTROLLER,
  REMOTE_IO_1,
  REMOTE_IO_2,
  //... will vary based on controllers being used...
  HMI_1,
  NUMBER_IO_DEVICES
} IO_devices_t;

typedef struct IO_link_t {
  IO_msg_ptr_t          IO_msg_ptr;
  uint8_t               IO_msg_size;
  IO_logic_ptr_t        IO_logic_ptr;
  //... other members as required by Equipment_setup.h ...
  //... members that vary based on the controller's SDK ...
} IO_link_t;
  

Ответ №1:

Когда вы сделаете это:

 typedef struct IO_link_t IO_link_t;
  

typedef Определяет тип. Вы также объявляете struct IO_link_t . Когда вы затем сделаете это:

 typedef struct IO_link_t {
  IO_msg_ptr_t          IO_msg_ptr;
  uint8_t               IO_msg_size;
  IO_logic_ptr_t        IO_logic_ptr;
  //... other members as required by Equipment_setup.h ...
  //... members that vary based on the controller's SDK ...
} IO_link_t;
  

Вы определяете struct IO_link_t то, что ранее не было определено, но вы также переопределяете тип IO_link_t . Вот откуда возникает ошибка. То же самое касается enum .

Вы можете исправить это, удалив typedef в точке, где определены struct и enum .

 enum IO_devices_t{
  MAIN_CONTROLLER,
  REMOTE_IO_1,
  REMOTE_IO_2,
  //... will vary based on controllers being used...
  HMI_1,
  NUMBER_IO_DEVICES
};

struct IO_link_t {
  IO_msg_ptr_t          IO_msg_ptr;
  uint8_t               IO_msg_size;
  IO_logic_ptr_t        IO_logic_ptr;
  //... other members as required by Equipment_setup.h ...
  //... members that vary based on the controller's SDK ...
};
  

Комментарии:

1. спасибо за быстрый ответ. Если я правильно понимаю, то я бы оставил свои прямые объявления (?? это правильный термин, я думаю, что нет) одинаковыми в Equipment_setup.h . Что, на мой взгляд, имеет большое значение, так это тот факт (о котором я забыл упомянуть), что в Controller_setup.h есть структуры и функции, которые также используют эти типы данных typedef.

2. Но вы помогли, и я думаю, что начинаю видеть разницу между тем, как я думаю, что все работает, и тем, как они работают на самом деле. Я вроде как понял, что typedef — это способ создания абревиатур, поскольку это было почти как макрос, где это избавляло меня от необходимости вводить enum или struct в начале, но само по себе это ничего не определяло. Но, как следует из названия, оно используется для определения символа.

3. В моем исходном примере вы можете думать об этом как о Equipment_setup . h Я определяю объявление, где, как в Controller_setup. h Я определяю определение. Итак, структура IO_link_t имеет одно объявление и одно определение, что нормально, но IO_link_t определяется в двух местах, чего нет.

4. Итак, если я все это правильно понимаю, одним из способов обойти это было бы просто избежать typedef и просто заменить все на struct IO_link_t ??

5. @MidnightRover Вы можете сохранить typedef , просто сделайте это только в одном месте.