предупреждение -Wlto-type-mismatch и структура с flexible array
- Войдите на сайт для отправки комментариев
Втр, 21/06/2022 - 15:55
продолжая копать аддон Кларка для СТМ32, наткнулся на такую проблему...
остальное в следующем сообщении, чтобы можно было редактировать ошибки
Ссылка на код аддона https://github.com/rogerclarkmelbourne/Arduino_STM32
плата - Generic STM32F103C series, контроллер stm32f103c8
Если включить при компиляции LTO, то сыпется куча предупреждений, все однотипные, такого плана:
Структура timer_dev описана в файле STM32F1/system/libmaple/include/libmaple/timer.h следующим образом
а инициализируется в STM32F1/system/libmaple/timer_private.h как
где макрос GENERAL_TIMER() описан так:
Не очень силен в теории, приходится догоняться поиском в гугле. Насколько я понял, предупреждение появляется из-за использования в структуре так называемого flexible массива -
который в структуре обьявлен без указания длины, а окончательно описывается одновременнно с инициализацией уже в конкретных экхемплярах.
Два дня поиска в гугле так и не дали ответа, как убрать это предупреждение. Нашел несколько тем на стек-оверфлоу, но либо без ответов, либо с бесполезным выводом в конце, что это мол баг GCC и нифига не поделать. Но прошло уже года три с того ответа, а в самом последнем arm-none-eabi-gcc 11.2.1 этот глюк присутсвует. В дополнение вычитал вроде как МИСРА вообще запрещает использовать flexible массивы в структурах.
Собственно вопрос - как переписать код, чтобы предупреждение исчезло? мне пока ничего лучшего в голову не приходит, кроме как заменить flexible массив обычным с фиксированной длиной, выбрав длину с запасом. Но насколько это правильное решение? Может есть более элегантный метод?
Ничего не понял.
Если в одном месте у Вас написано
а в другом
То, почему Вас удивляет сообщение: "
type of
'timer4'
does not match original declaration
"?почему Вас удивляет сообщение: "
type of
'timer4'
does not match original declaration
"?как я себе это понимаю, тип timer4 один и тот же - timer_dev. А = GENERAL_TIMER(4); - это уже инициализация.
Разве мы не можем в одном юните написать
а в другом
разве это будут переменные разных типов?
Добавлю, что без опции -flto предупреждения нет.
как я себе это понимаю, тип timer4 один и тот же - timer_dev. А = GENERAL_TIMER(4); - это уже инициализация.
Ну, и так, и не так.
timer_dev - это т.н. недоопределённый тип ("incomplete type"), т.к. он содержит член - массив неопределённой длины, который сам по себе существовать не может (попробуйте просто объявить "int a[];" вне структуры) и типа как такового не имеет.
Чтобы убедиться, что этот член не имеет типа, посмотрите на этот скетч:
Всё классно работает. Результат:
Заметьте, что sizeof обоих массивов - 2, т.е. член b никак не влияет на размер структуры в обоих случаях. Хотя, в проинициализированном варианте этот массив получил правильные значения.
А теперь попробуйте раскомментировать строки 21 и 22. Увидите страшную ругань: "error: invalid application of 'sizeof' to incomplete type 'int []'".
т.е. тип члена b - недоопределён, а значит, недоопределён и тип всей структуры.
Добавлю, что без опции -flto предупреждения нет.
LTO - штука, во многом, эвристическая и ей очень важно точно знать, что типы действительно абсолютно одинаковые и никаких фокусов там будет. Потому, недоопределённые типы для LTO всегда различны. Здесь важно слово "всегда". Попробуйте, например, оба свои массива проинициализировать одинаково. Почти уверен, что LTO всё равно ругнётся (т.к. типы по-прежнему недоопределены)! Если не ругнётся, значит в очередной версии LTO они таки разрешили этот частный случай. Раньше ругалось, зуб даю.
Если бы это было не так, то перед LTO вставали бы уж слишком интеллектуальные задачи. Например, если бы он посчитал, что Ваши timer4 одинаковые и, обнаружив, что они не используются, решил бы их удалить. Что ему удалять? По sizeof? Или с учётом массива, который у одной переменной есть, а у другой - нет?
Евгений, если я понял правильно - то выходит я "угадал" и причина предупреждения компилятора именно в "неполном массиве"
voidFuncPtr handlers[];
Точнее в том, что первоначально структра декларируется с неполным массивом, а инициализируется уже полным, поэтому типы получаются разными, правильно?
Проверил, замена на массив фиксированного размера полностью убирает все предупреждения.
Спасибо за обьяснения.
имя типа и имя переменной - одинаковы(timer_dev), по идее это не варнинг а ошибка.
P.S. Нет, это я самдурак.
Это не имя переменной, это имя синонима типа, потому что typedef.
Вполне может быть, в Си не силён. Нахрена их 2 одинаковых описания :)))
Потмоу что иначе в C нужно писать каждый раз struct