Arlleex 172 5 августа, 2023 Опубликовано 5 августа, 2023 · Жалоба @xvr, выше я свое сообщение дополнил Цитата Да, порядок вставки инклудов препроцессором (прим. - дополнил позже) - строгий. А вторая часть предложения Цитата И да - от порядка следования подключений инклудов может зависеть собираемость проекта. была воспринята некоторыми как просто невозможный факт. На примере FreeRTOS (это достаточно известное ПО?) я все показал. 34 минуты назад, xvr сказал: В общем случае не должен, но могут быть исключения. Конечно могут - вот и я писал, что от порядка может зависеть собираемость (и какие-то особенности) проекта. P.S. Заголовки заголовкам рознь. Часто бывает, что для нужд .h-ника он сам должен включать кучу других .h-ников. Это порождает кучу зависимостей, при этом, когда такой монстр подключается в .c-шник, программист, как правило, думает, что он подключит только этот файл - а нет, подключается еще 100500 файлов. Каждый из которых замусоривает пространство имен и т.д. А в один прекрасный момент программист, сам того не осознавая, попытается сослаться из одного заголовка на другой, который через 100 зависимостей итак уже включен в первый - т.е. классическое замыкание включений, которое будет долго искать. Поэтому в заголовочниках, как правило, по минимуму подключений сторонних хедеров, все нужные заголовки подключаются в исходнике .c. Дальше - когда в заголовочнике находятся условные директивы, от которых зависит, например, реализация функции - программная или аппаратная. В конкретном исходнике перед подключением такого хедера обязательно нужно выбрать опцию. И тут тоже появляется зависимость от порядка включения файлов. И да - злоупотреблять такими мерами не стоит, но утверждать, что так не может быть и все кто так пишет - говнокодеры - пустой треп. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 231 5 августа, 2023 Опубликовано 5 августа, 2023 · Жалоба 10 часов назад, repstosw сказал: При портировании библиотек libjpeg и libspeexdsp и сборки общего проекта, линковщик выдаёт ошибку: не определены функции: __close, remove, __lseek, __read, __open Хотя я нигде их не использую. Значит эти библиотеки сами их вызывают. 10 часов назад, repstosw сказал: Тем не менее, линковщик считает, что они нужны. Почему ? Видимо потому, что они используются библиотеками, кэп. Не обязательно вызываются, достаточно чтобы хотя бы держали указатели на них. 10 часов назад, repstosw сказал: Как в IAR включить вырезание всех неиспользуемых функций? В GCC это делается легко. IAR это делает по умолчанию. Чтобы неиспользуемое попало в итоговый образ - это ещё нужно постараться. 10 часов назад, repstosw сказал: В GCC не нужно писать никаких заглушек. Значит они уже там есть. Чудес не бывает. 10 часов назад, repstosw сказал: И всё-же, как более элегантнее и правильнее разрулить эту ситуацию? Не использовать кривых "либ". Или внимательнее изучить их требования. 3 часа назад, razrab83 сказал: начните с того, чтобы от порядка инклуде сборка не зависела. Это так просто. Начнет получаться. А вы - начните с того, что объясните создателям компиляторов, использующих предкомпилённые include, что они неправы. Таких компиляторов как "Visual Studio" и многих других. А без предкомпилённых инклудов, время сборки тяжёлых проектов вырастает многократно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ericN 3 6 августа, 2023 Опубликовано 6 августа, 2023 · Жалоба В 05.08.2023 в 16:01, Arlleex сказал: Часто бывает, что для нужд .h-ника он сам должен включать кучу других .h-ников. Это порождает кучу зависимостей, при этом, когда такой монстр подключается в .c-шник, программист, как правило, думает, что он подключит только этот файл - а нет, подключается еще 100500 файлов. Каждый из которых замусоривает пространство имен и т.д. А в один прекрасный момент программист, сам того не осознавая, попытается сослаться из одного заголовка на другой, который через 100 зависимостей итак уже включен в первый - т.е. классическое замыкание включений, которое будет долго искать. Поэтому в заголовочниках, как правило, по минимуму подключений сторонних хедеров, все нужные заголовки подключаются в исходнике .c. если из .h-ника убрать включения других .h-ников, которые нужны, то вы все другие .h-ники включите в .с. А эти другие h-ники тоже не включили для своих нужд другие h-ники, и их прийдется включить в .с. ..... В итоге вы так же все 100500 файлов подключите в свой .с и получите ровно точно такое же ваше "замусоривание" и т.п. И вместо того, чтобы сделать одно включение и писать дальше программу, вы будете сыскной работой заниматься, подключать все 100500 h-ников, да ещё и порядки их соблюдать. И так в каждом .с, где понадобиться этот один единственный ашник. Поэтому, как правило, в заголовочных файлах делают все подключения сторонних хидеров для собственных нужд, а не в исходнике .с. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
razrab83 21 6 августа, 2023 Опубликовано 6 августа, 2023 · Жалоба В 05.08.2023 в 13:52, Arlleex сказал: Сюда же (выше ссылка). Переместите включение, например, task.h перед FreeRTOS.h и соберите. Попробовал. Да, действительно, task.h перед FreeRTOS.h - не собирается. Но, в task.h в самом начале #ifndef INC_TASK_H #define INC_TASK_H #ifndef INC_FREERTOS_H #error "include FreeRTOS.h must appear in source files before include task.h" #endif получил этот вывод. Но во первых, тут авторы позаботились и сделали проверку и вывод. Программисту не нужно заниматься сыском. Во-вторых что мешало сделать так? #ifndef INC_TASK_H #define INC_TASK_H #include "FreeRTOS.h" #ifndef INC_FREERTOS_H #error "include FreeRTOS.h must appear in source files before include task.h" #endif Добавил #include "FreeRTOS.h" в #include "timers.h", #include "queue.h", #include "semphr.h" - теперь тусуй их в любой последовательности и всё собирается. далее... вот ваша ссылка на TI Цитата All source code using FreeRTOS APIs, including FreeRTOS kernel itself MUST include “FreeRTOSConfig.h” before any other FreeRTOS .h files. Да, прямо уже согласился с порядком... но в глубине мыслей, а почему FreeRTOSConfig.h не вставить в FreeRTOS .h? Зачем они его вынесли?.... открываю проект с FreeRTOS, инклуде такие #include "FreeRTOS.h" #include "timers.h" #include "queue.h" #include "semphr.h" #include "task.h" #include "event_groups.h" А где же FreeRTOSConfig.h??? Провалился в FreeRTOS.h и там /* Application specific configuration options. */ #include "FreeRTOSConfig.h" Ну правильно же сделали. Может раньше в старых версиях ртос FreeRTOSConfig.h не было в FreeRTOS.h. Сейчас он там есть. Добавить в "task.h" #include "FreeRTOS.h" - и ни какой зависимости от порядка следования include нет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 231 6 августа, 2023 Опубликовано 6 августа, 2023 · Жалоба 1 час назад, ericN сказал: Поэтому, как правило, в заголовочных файлах делают все подключения сторонних хидеров для собственных нужд, а не в исходнике .с. Не факт. Подключение всей иерархии хидеров конечно упрощает работу, но в тоже время и может сильно замедлить её. Когда делаете изменения в небольшом .h-файле и это влечёт пересборку всего огромного проекта. Из-за того, что он оказался включён прямо в .cpp или косвенно (через другие .h). Вот к примеру есть у вас структура struct, которая объявлена в каком-то .h (a.h). И есть другой .h-файл (b.h), в котором объявлены функции, принимающие указатель на эту структуру в качестве аргумента. И этот другой .h-файл может быть включен (прямо или косвенно) в кучу .cpp-файлов. Которые не работают непосредственно с этой структурой, но принимают/передают указатели на неё. А есть один .cpp-файл, который как раз работает с содержимым этой структуры. В таком случае в a.h вы объявляете эту структуру со всеми её членами (полное объявление). А в файле b.h - делаете только неполное объявление структуры. Для указателей на неё - этого достаточно. Но теперь, если сделать так, то при изменении содержимого структуры, у вас меняется только a.h и, соответственно - перекомпилится только один .cpp, в который он включен. А масса других .cpp-файлов проекта - не перекомпилится. Соответственно работа с проектом может ускоряться многократно (для больших и тяжёлых проектов). 23 минуты назад, razrab83 сказал: Во-вторых что мешало сделать так? Не следование рекомендациям производителей какого-то софта или чипа - это хождение по граблям. Если даже прямо сейчас они не прилетели вам в лоб, то обязательно прилетят потом, когда вы давно забудете, что сами же и заложили эту кучу г*вна себе под ковёр. PS: Вы считаете себя умнее авторов FreeRTOS? И считаете, что лучше разбираетесь в их продукте, чем они сами?? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ericN 3 6 августа, 2023 Опубликовано 6 августа, 2023 (изменено) · Жалоба В 06.08.2023 в 14:27, jcxz сказал: А в файле b.h - делаете только неполное объявление структуры. Можно на примере? Изменено 6 августа, 2023 пользователем ericN Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 231 6 августа, 2023 Опубликовано 6 августа, 2023 · Жалоба 3 минуты назад, ericN сказал: что такое "неполное объявление структуры"? Это другой тип данных и потом делается явное приведение типа? Можно на примере? .h-файл: #include ... ... class CMainDlg; //ни в каких .h включённых в этот .h, CMainDlg не объявлен BOOL Export(CMainDlg *, uint); Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ericN 3 6 августа, 2023 Опубликовано 6 августа, 2023 (изменено) · Жалоба В 06.08.2023 в 14:46, jcxz сказал: .h-файл: #include ... ... class CMainDlg; //ни в каких .h включённых в этот .h, CMainDlg не объявлен BOOL Export(CMainDlg *, uint); Понятно о чем вы. Я так часто делаю. Только я называю это прямое объявление класса. Но это не отменяет выше мной сказанного.... в заголовочных файлах делают все подключения сторонних хидеров для собственных нужд, а не в исходнике .с. В данном хидоре вы сделали прямое объявление класса, после этого этот хидер знает, что CMainDlg - это класс, который будет определён позднее. Теперь у хидера нет нужны в определении класса. И при этом, вы потом вставите свои b.h и а.h в свой исходник в любой очерёдности. Программа скомпилируется и соберёться. Изменено 6 августа, 2023 пользователем ericN Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
razrab83 21 6 августа, 2023 Опубликовано 6 августа, 2023 · Жалоба 44 минуты назад, jcxz сказал: Не следование рекомендациям производителей какого-то софта как раз таки я последовал рекомендациям производителей софта и включил FreeRTOS.h перед task.h Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Xenia 42 6 августа, 2023 Опубликовано 6 августа, 2023 · Жалоба 23 часа назад, jcxz сказал: IAR это делает по умолчанию. Чтобы неиспользуемое попало в итоговый образ - это ещё нужно постараться. У меня точно такое впечатление - все функции, которые не используются (т.е. нигде не вызываются), компилируются, но к результирующей прошивке не линкуются. Просьба к топикстартру - могли бы вы выложить этот проект целиком? А то архив rs.zip я скачала, то там для IAR'а нечего нет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 231 6 августа, 2023 Опубликовано 6 августа, 2023 · Жалоба 1 час назад, ericN сказал: Понятно о чем вы. Я так часто делаю. Только я называю это прямое объявление класса. В языке си это называется так, как я написал: "неполный тип", а не какой не "прямой". Зачем придумывать свой птичий язык, понятный только вам? https://learn.microsoft.com/ru-ru/cpp/c-language/incomplete-types?view=msvc-170 https://pvs-studio.ru/ru/blog/terms/6528/ 1 час назад, ericN сказал: CMainDlg - это класс, который будет определён позднее. Теперь у хидера нет нужны в определении класса. И при этом, вы потом вставите свои b.h и а.h в свой исходник в любой очерёдности. Не так..... Я не "вставлю позднее это определение". b.h - вставлен в кучу файлов (прямо или косвенно), a.h - только в один (ну или - в некоторые). a.h не будет нигде вставлен в иерархию вложенных include b.h. class CMainDlg - объявлен, но не будет более позднего его полного объявления для ветки b.h. Для неё так и останется только: class CMainDlg; 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ericN 3 6 августа, 2023 Опубликовано 6 августа, 2023 (изменено) · Жалоба В 06.08.2023 в 16:46, jcxz сказал: Зачем придумывать свой птичий язык, понятный только вам? вы написали class - ключевое слово с++. в с++ это называется так, как я написал. В 06.08.2023 в 16:46, jcxz сказал: class CMainDlg - объявлен, но не будет более позднего его полного объявления для ветки b.h Да, там где оно не нужно, там не будет. Будет для тех, кто будет использовать члены структуры/класса CMainDlg. Суть от этого не меняется: в заголовочных файлах делают все подключения сторонних хидеров для собственных нужд, а не в исходнике .с. В вашем .h нет такой нужны. И очерёдность a.h и b.h не положит сборку. Изменено 6 августа, 2023 пользователем ericN Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
razrab83 21 6 августа, 2023 Опубликовано 6 августа, 2023 · Жалоба В 04.08.2023 в 18:19, Arlleex сказал: Ну вот прям ни разу нет. что ни разу нет? По дефолту, т.е. если ни каких специальных указаний компилятору не давать - char знаковый. В 04.08.2023 в 18:19, Arlleex сказал: Что в этом плохого? Плохого в этом то, что неявные приведения типа - это источник проблем. При таком неявном приведении типа вам даже си компилятор дает предупреждение. Не было бы в это ни чего плохого - не было бы предупреждений. В с++ убрали неявные приведения типа оставили их только для совместимости с си, но добавили касты и рекомендуют приведения делать кастами. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 172 6 августа, 2023 Опубликовано 6 августа, 2023 · Жалоба 6 часов назад, ericN сказал: Поэтому, как правило, в заголовочных файлах делают все подключения сторонних хидеров для собственных нужд, а не в исходнике .с. Подключения там делают только тех файлов, без которых исходный заголовочник не может быть обработан в месте, где его подключили. А хидеры бывают не только такие - например, всякие конфигурационные (как в упомянутом FreeRTOS), с абстрактными макрос-функциями, с объявлениями неполных типов и т.д. Их нет смысла подключать нигде, кроме как в нужном исходнике .c. Поэтому и возникает потребность в очередности подключений. Да, редко, но бывает. Иначе такие вопросы никогда не поднимались бы во всем мире, а не только тут. 5 часов назад, razrab83 сказал: Добавил #include "FreeRTOS.h" в #include "timers.h", #include "queue.h", #include "semphr.h" - теперь тусуй их в любой последовательности и всё собирается. И теперь осталось сообщить 10 коллегам, чтобы тоже у себя поправили в репозиториях, а потом при обновлении версии ядра - все по новой. 1 час назад, razrab83 сказал: что ни разу нет? По дефолту, т.е. если ни каких специальных указаний компилятору не давать - char знаковый. Вы стандарт давно (или вообще хоть раз) открывали? Цитата Плохого в этом то, что неявные приведения типа - это источник проблем. Вопрос заключался совсем в другом - работодатель хочет знать, насколько вы в курсе базовых особенностей низкоуровневых языков программирования, приходилось ли вам открывать стандарт хоть раз в жизни или вы только кнопочки подкрашивали на шарпе, закончив позавчера скиллфэктори. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 231 6 августа, 2023 Опубликовано 6 августа, 2023 · Жалоба 27 минут назад, Arlleex сказал: Их нет смысла подключать нигде, кроме как в нужном исходнике .c. Поэтому и возникает потребность в очередности подключений. Да, редко, но бывает. А ещё бывает нужно в некоторых случаях один и тот же .h-файл подключить несколько ряд подряд в одном и том же файле. Вот например фрагмент include.h из одного из моих проектов на ARM: ... #undef CCLK_VAL #define CCLK_VAL CCLK_VAL_MH #define CCLK_SRC CCLK_SRC_MH #include "clk.h" #define CCLK_VAL CCLK_VAL_ML #define CCLK_SRC CCLK_SRC_ML #include "clk.h" #define CCLK_VAL CCLK_VAL_MT #define CCLK_SRC CCLK_SRC_MT #include "clk.h" ... clk.h подключается трижды. В clk.h выполняется расчёт + валидация ряда констант, зависимых от частоты тактирования МК (всякие коэффициенты PLL, делители шин и разной периферии и т.п.). Расчёт выполняется на основе входных значений желаемой тактовой частоты и источника тактирования (CCLK_VAL, CCLK_SRC). PS: Расстрелять? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться