Да тут у нас циклическая зависимость по интерфейсам! Такого не потерпит ни один язык, и Си тоже.
Если в трёх модулях есть какие-то общие типы, их обычно выносят в отдельный хедер с названием вроде «MyUnitDefines.h».
Как это выглядит технически? Пусть Unit3 описывает переменную extern Type1 var3;
// Начало Unit1
// Начало Unit2
// Начало Unit3
// Начало Unit1
// Поскольку сработала защита от двойного включения, второго включения не было.
// Так что кода typedef int Type1; к сожалению, йок.
// Конец Unit1
extern Type1 var3; // Type1, естественно, не определён.
// Си (как минимум старые редакции) это понимает как extern int Type1 var3.
// Конец Unit3
// Конец Unit2
// Определение стоит ниже по коду, но это ПЕРВОЕ включение.
typedef int Type1;
// Конец Unit1
(Да, препроцессор тупо копипастит код и не больше.)
Циклическую зависимость по реализациям (то есть в C-файлах) большинство языков терпят. И Си тоже.