Так.. У меня что-то вроде курицы и яйца.
У меня есть Controller_setup.h и Equipment_setup.h, которые используют определения типов, определенные в другом. Я мог бы много писать здесь об обосновании того, почему это так, но воздержусь от этого, если только кто-то действительно не хочет знать (хотя в основном это была попытка заставить код в Equipment_setup.c/h работать с различными системами контроллера, просто имея другой Controller_setup.h).
На предыдущем контроллере и компиляторе (контроллер использовал процессор ARM, а мы использовали компилятор IAR и IDE) мы разработали код, и я смог перенаправить объявление/переопределение typedefs, и это сработало. Это даст нам много предупреждений, но оно будет компилироваться и работать.
Теперь, когда мы на самом деле пытаемся перенести на другой контроллер, используя другую 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.
Сообщение об ошибке:
- error: [12993] redefinition of typedef 'IO_link_t'
- error: [13256] previous declaration of 'IO_link_t' was here
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;
Когда вы делаете это:
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 ...
};
Но вы помогли, и я думаю, что начинаю видеть разницу между тем, как я думаю, что вещи работают, и тем, как они работают на самом деле. Я примерно понял, что typedef — это способ создания аббревиатур в том смысле, что он был почти как макрос, избавляющий меня от необходимости вводить enum или struct в начале, но на самом деле он ничего не определял сам по себе. Но, как следует из названия, оно используется для определения символа.
В моем исходном примере вы можете думать об этом так, как будто в Equipment_setup.h я определяю объявление, а в Controller_setup.h я определяю определение. Таким образом, структура IO_link_t имеет одно объявление и одно определение, что нормально, но IO_link_t определяется в двух местах, что не так.
Так что, если я все правильно понимаю, одним из способов было бы просто избежать typedef и просто заменить все на структура IO_link_t??
@MidnightRover Вы можете сохранить typedef
, просто сделайте это только в одном месте.
Обратите внимание, что C11 (и C18) позволяют вам определять typedef
в два раза дольше, если он идентичен для каждой связи. Я не использовал эту функцию (сознательно) и не собираюсь этого делать. Однако он существует — см. C11 §6.7 Декларации ¶3: имя typedef может быть переопределено для обозначения того же типа, что и в настоящее время, при условии, что этот тип не является изменяемым типом.
Спасибо за быстрый ответ. Если я правильно понимаю, то я бы оставил свои предварительные объявления (?? это правильный термин, я думаю, что нет) такими же в Equipment_setup.h. Что-то, что я думаю, имеет большое значение, так это тот факт (о котором я забыл упомянуть), что в Controller_setup.h есть структуры и функции, которые также используют эти типы данных typedef.