Без присвоения - можно (но это не решает пробелмы ТС). Обычно, я
делаю только глобальные внешние объявления. Локальные переменные
остаются просто в коде *.c, без упоминаний в заголовках. Например: typedef struct {
unsigned Touch: 1;//Touch detected!
unsigned ADCdata : 1;//ADC cycle completed, 4 channels converted
unsigned LagDetected : 1;//Main code lag detected (debug purpose)
} Flags_t;
extern volatile Flags_t Flags;//Flags global declaration
Затем, в коде, вне процедур:
volatile Flags_t Flags = { 0 };
Получается, что определение у меня только одно, только в том файле, где происходит объявление только в одном файле, вне функции. Внутри функции будет обращение к переменной. А вот объявлений может быть много - везде, где требуется обращение к этой глобальной переменной и куда включён заголовочный файл с объявлением.
P.S. Именно так и решается проблема ТС с определениями. Не делать определения в заголовочных файлах. А делать только объявления. Определение делать только одно, в том файле, который будет скомпилирован в любой конфигурации проекта, например, в main.c. Ну и не забывать, что если к переменной возможно обращение из прерывания, объявлять и определять её как volatile.