Вопросы по С/С++ (СИ)
Re: Вопросы по С/С++ (СИ)
Ну удалите эти сегменты тогда из линкера.
- Реклама
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Очень просто - компилятору эти файлы передаются как аргументы командной строки.aam писал(а):А вообще, как компилятор определяет из каких сишников состоит именно этот проект?
Вот, например, мой Makefile под gcc (писал библиотеку для графического дисплея для AVR):
Код: Выделить всё
TARG=ks0108lib
SRCS = main.c ks0108.c
MCU = atmega16
F_CPU = 16000000L
OPTIMIZE = -Os -mcall-prologues
CFLAGS = -g -Wall -Werror -lm $(OPTIMIZE) -mmcu=$(MCU) -DF_CPU=$(F_CPU)
LDFLAGS = -g -Wall -Werror -mmcu=$(MCU)
OBJS = $(SRCS:.c=.o)
CC = avr-gcc
OBJCOPY = avr-objcopy
AVRDUDE = avrdude
all: $(TARG)
$(TARG): $(OBJS)
$(CC) $(LDFLAGS) -o $@.elf $(OBJS) -lm
$(OBJCOPY) -O binary -R .eeprom -R .nwram $@.elf $@.bin
$(OBJCOPY) -O ihex -R .eeprom -R .nwram $@.elf $@.hex
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<Код: Выделить всё
$(CC) $(CFLAGS) -c -o $@ $<
$(CC) $(LDFLAGS) -o $@.elf $(OBJS) -lmКод: Выделить всё
avr-gcc -g -Wall -Werror -lm -Os -mcall-prologues -mmcu=atmega16 -DF_CPU=16000000L -c -o main.c ks0108.c
avr-gcc -g -Wall -Werror -mmcu=atmega16 -o ks0108lib.elf main.o ks0108.o -lmЛюбой другой компилятор по сути делает то же самое - те файлы, которые перечислены в "проекте", просто перечисляются как аргументы командной строки исполняемого файла компилятора
Re: Вопросы по С/С++ (СИ)
А причем здесь компиль, если это делает препроцессор??!!
Re: Вопросы по С/С++ (СИ)
цепляю другие сишники проекта через include
У-у-у, институт - это точно не аргумент (чаще даже контр-аргумент, "послушай и делай наоборот"). Мы там тоже тако-о-ое в курсачах воротили...Но насколько помню, даже в институте сишники вроде цепляли.
В общем, дело обстоит так. Включаются, разумеется, только .h-файлы. Они нужны для того, чтобы в момент компиляции конкретного .c-файла компилятор знал, что те функции, которых он не нашел там же, на самом деле где-то есть. Тогда в то место, где такая функция вызывается, он вставляет пометку для линкера о вызове, а линкер дальше разбирается.
Процесс сборки проекта упрощенно выглядит так:
1. IDE запускает компилятор для каждого .с-файла, добавленного в проект. При этом получаются объектные файлы (.o). Они содержат код вперемешку с указаниями о вызове тех функций, которых в них самих нет.
2. IDE запускает линкер, указывая ему на полученные объектные файлы. Линкер смотрит, что откуда вызывается, и собирает результирующий бинарник, подставляя требуемые куски кода/вызовы в нужные места (и попутно правя адресацию и размещение переменных).
3. Если необходимо, IDE запускает конвертер, который преобразует выходной файл к нужному формату (например, .elf в .hex) и другие утилиты, типа подсчета занятой памяти и т.п.
Если включать прямо .c-файлы, то с большой вероятностью произойдет конфликт при линковке, если и не при компиляции - например, на одно и то же место будут претендовать два участка кода. Ну и еще много сюрпризов может произойти.
По этой же причине в заголовочниках нужен include guard -
Код: Выделить всё
#ifndef _SOME_UNIQUE_FILE_ID_
#define _SOME_UNIQUE_FILE_ID_
...
#endif
Разница между теорией и практикой на практике гораздо больше, чем в теории.
- BCluster
- Собутыльник Кота
- Сообщения: 2512
- Зарегистрирован: Пн апр 06, 2009 19:33:29
- Откуда: Молдова, Кишинев
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Сишники из makefile берутся. Когда вы в IAR добавляете в проект файл, он его автоматически в makefile записывает (у IAR не совсем классический makefile, но все же)
- Реклама
Re: Вопросы по С/С++ (СИ)
Кстати, показал эту тему своему другу, Ъ-программисту, выпускнику матмеха, дабы он проверил то объяснение, что я дал выше. Вот резюме профессионала:

По-моему, исчерпывающе.m08pvv писал(а): ...
Короче, инклудить *.с - это как жрать суп вилкой
Можно, но не нужно - есть ложка
Да и вилку ещё мыть сложнее
Поэтому в армии дают только ложки
// ни ножей, ни вилок
Разница между теорией и практикой на практике гораздо больше, чем в теории.
- Алексей FAV
- Вымогатель припоя
- Сообщения: 579
- Зарегистрирован: Пн янв 01, 2007 22:27:34
- Откуда: Оренбург
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
а я все равно не понимаю, есть суп вилкой.не удобно но мне нравится. 
P.S. простите я нечаянно
P.S. простите я нечаянно
добрый, когда сплю. И не стоит уж так детализировать инженеры или радиолюбители. Для меня тот кто с удовольствием, как любитель или профессионал что то творит уже инженер, даже если без диплома...
- BCluster
- Собутыльник Кота
- Сообщения: 2512
- Зарегистрирован: Пн апр 06, 2009 19:33:29
- Откуда: Молдова, Кишинев
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Простите меня, но я в УПОР НЕ ВТЫКАЮ, нафиг вообще инклюдить С файлы. Мне это даж в голову не приходило никогда 
Re: Вопросы по С/С++ (СИ)
Эх, хотел было расписать, да опоздал - всё уже рассказали 
От себя посоветую поиграться со сборкой проекта без IDE. Вооружиться голым компилятором и блокнотом, написать программку в пару строк, собрать, добавить пару файлов - снова собрать. Очень помогает пониманию.
От себя посоветую поиграться со сборкой проекта без IDE. Вооружиться голым компилятором и блокнотом, написать программку в пару строк, собрать, добавить пару файлов - снова собрать. Очень помогает пониманию.
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Соглашусь, IDE часто способствует непониманию того, "как оно там внутри работает".
И хотя я, например, для редактирования C-шного кода использую QtCreator, но только по сути в качестве удобного текстового редактора с подсветкой синтаксиса, удобным древовидным списокм файлов проекта, автодополнением и возможностью рефакторинга кода. Но все правила компиляции прописаны вручную в Makefile.
И хотя я, например, для редактирования C-шного кода использую QtCreator, но только по сути в качестве удобного текстового редактора с подсветкой синтаксиса, удобным древовидным списокм файлов проекта, автодополнением и возможностью рефакторинга кода. Но все правила компиляции прописаны вручную в Makefile.
Re: Вопросы по С/С++ (СИ)
А QtCreator не сможет нормально сделать проект, если это не Qt-проект. Либо ковырять его придётся до посинения. Так что да, с ним проще вручную Makefile настроить.
А IDE замечательная.
А IDE замечательная.
Re: Вопросы по С/С++ (СИ)
Короче, это все круто, но тогда полная байда с дефайнами выходит.
Например, у меня фаылы используют какие-то константы типа "MCU_CLOCK" Определяется она естественно в начале проги. Но тогды выходит, что в библиотечный универсальный h-файл я должен включать "пользовательский" h-файл основной проги. Библиотека моя в данном случае, но в общем случае выходит бред - захочу использовать в другой проге - придется переписывать либу.
Файл main.h:
Библиотека протокола RC5 "RC5.h":
Файл RC5.c:
В итоге компилер естесвтенно орет что не может найти RCU_CLOCK и т. д., но я не могу их объявить в файле "RC5.h", т. к. нарушу принцип "неприкосновенности" и универсальности библиотеки.
Т. е. собственно вопрос: а как тогда дефайнить настраиваемые параметры библиотек в пользовательской проге?
Например, у меня фаылы используют какие-то константы типа "MCU_CLOCK" Определяется она естественно в начале проги. Но тогды выходит, что в библиотечный универсальный h-файл я должен включать "пользовательский" h-файл основной проги. Библиотека моя в данном случае, но в общем случае выходит бред - захочу использовать в другой проге - придется переписывать либу.
Файл main.h:
Код: Выделить всё
#define RCU_CLOCK 128
#define RCU_IR_PORT PORTD
#define RCU_IR_PIN 2
#include "RC5.h" //подключаю библиотеку RC5
Код: Выделить всё
//на основе этих констант объявляются другие константы
#define PW_SHORT_MIN (889/RCU_CLOCK - 889/(4*RCU_CLOCK))
Код: Выделить всё
#include "RC5.h"
...
pin_st = !TST_PIN(RCU_IR_PORT,RCU_IR_PIN);
...
ну и т. п., т. е. используются указанные константы, хотя в файле "RC5.h" не объявлены
Т. е. собственно вопрос: а как тогда дефайнить настраиваемые параметры библиотек в пользовательской проге?
Re: Вопросы по С/С++ (СИ)
Неприкосновенный должен быть сишник. А вот h может быть вполне прикосновенный. Можно забацать отдельный хедер для таких настроек.aam писал(а):но я не могу их объявить в файле "RC5.h", т. к. нарушу принцип "неприкосновенности" и универсальности библиотеки.
Re: Вопросы по С/С++ (СИ)
А, типа так:
Файл RC5.h
При этом грубо говоря если я (юзер библиотеки) забыл создать файл settings.h, то препроцессор заорет что файл не найден и юзер залезет в H-файл и прочтет что надо его создать.
Т. е. это норм считается, не "вилкой суп"?
Так я и не понял преимуществ раздельной линковки... И почему инклюдить синики - через ж*у...
Ведь можно сишних цеплять к H в конце этого H и тогда на компилятор пойдет все одним куском.
Файл RC5.h
Код: Выделить всё
/* Readme:
Для работы с библиотекой необходимо создать файл Settings.h и в нем объявить константы RCU_CLOCK, RCU_PORT
*/
#include "settings.h"
...
Т. е. это норм считается, не "вилкой суп"?
Так я и не понял преимуществ раздельной линковки... И почему инклюдить синики - через ж*у...
Ведь можно сишних цеплять к H в конце этого H и тогда на компилятор пойдет все одним куском.
Последний раз редактировалось aam Вт янв 21, 2014 11:29:49, всего редактировалось 1 раз.
- BCluster
- Собутыльник Кота
- Сообщения: 2512
- Зарегистрирован: Пн апр 06, 2009 19:33:29
- Откуда: Молдова, Кишинев
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Так происходит из-за неправильной архитектуры проекта.
Варианта два:
1. Держать в каждом проекте свой main.h, который будет подключаться ко всем модулям. Тогда, не будет необходимости писать в каждом файле десяток инклюдов - только один.
2. Вместо дефайна сделать функцию инициализации, в которую передавать параметрами эти дефайны, а она в свою очередь проинициализирует какую-то переменную, которую потом и использовать в программе
У нас в проекте около 50 модулей, и есть файл main.h в котором определены все инклюды. А каждый сишник начинается с #include "main.h". Это требует только обертки от множественного инклюда, как было указано несколько постов назад.
Если хотите, чтобы библиотека использовалась другими людьми, да и вообще для мелких проектов, выберите второй способ.
Варианта два:
1. Держать в каждом проекте свой main.h, который будет подключаться ко всем модулям. Тогда, не будет необходимости писать в каждом файле десяток инклюдов - только один.
2. Вместо дефайна сделать функцию инициализации, в которую передавать параметрами эти дефайны, а она в свою очередь проинициализирует какую-то переменную, которую потом и использовать в программе
У нас в проекте около 50 модулей, и есть файл main.h в котором определены все инклюды. А каждый сишник начинается с #include "main.h". Это требует только обертки от множественного инклюда, как было указано несколько постов назад.
Если хотите, чтобы библиотека использовалась другими людьми, да и вообще для мелких проектов, выберите второй способ.
Последний раз редактировалось BCluster Вт янв 21, 2014 11:33:22, всего редактировалось 1 раз.
Re: Вопросы по С/С++ (СИ)
1-й вариант - собственно что я и сказал.
2-й вариант годится для компа. Но не для микроконтроллера! Т. к. это расточительное использование и без того малых ресурсов. А то так можно дожить до того, что диод от мега 128 зажигать будем
Я хочу для начала разобраться как НАДО писать проги и как НЕ НАДО. Проги я пишу для микроконтроллеров, как вы поняли))
2-й вариант годится для компа. Но не для микроконтроллера! Т. к. это расточительное использование и без того малых ресурсов. А то так можно дожить до того, что диод от мега 128 зажигать будем
А 1-й способ для чего тогда?BCluster писал(а):Если хотите, чтобы библиотека использовалась другими людьми, да и вообще для мелких проектов, выберите второй способ.
Я хочу для начала разобраться как НАДО писать проги и как НЕ НАДО. Проги я пишу для микроконтроллеров, как вы поняли))
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Не знаю как насчёт других компиляторов, но у того же gcc (и avr-gcc, само собой) есть ключ D (http://www.rapidtables.com/code/linux/gcc/gcc-d.htm).aam писал(а):Короче, это все круто, но тогда полная байда с дефайнами выходит.
Например, у меня фаылы используют какие-то константы типа "MCU_CLOCK" Определяется она естественно в начале проги.
На картинке со скриншотом QtCreator выше видна, например, переменная F_CPU.
Компилятору она передаётся в виде avr-gcc .... -D F_CPU=16000000L
Это по сути равнозначно тому, что в каждый исходный файл проекта добавлена строка #define F_CPU=16000000L.
Поэтому, используя эту опцию, можно не заморачиваться о разных settings.h.
Re: Вопросы по С/С++ (СИ)
aam
Используйте первый способ. Сделайте какой-нибудь global.h со всеми константами, и цепляйте куда надо.
Но правильным всё-таки является второй, с функциями инициализации. При грамотном написании и применении директив компилятора вы много не потеряете, но зато получите универсальность и совместимость. А хотите экономить - пишите всё в одном файле, а переносимость обеспечивайте с помощью копипаста
Используйте первый способ. Сделайте какой-нибудь global.h со всеми константами, и цепляйте куда надо.
Но правильным всё-таки является второй, с функциями инициализации. При грамотном написании и применении директив компилятора вы много не потеряете, но зато получите универсальность и совместимость. А хотите экономить - пишите всё в одном файле, а переносимость обеспечивайте с помощью копипаста
Re: Вопросы по С/С++ (СИ)
Тут по мимо самой памяти для констант еще как бы такой момент:
Если я умножаю/делю/складываю дефайновские константы, то все эти операции делает препроцессор и в код ничего не идет. Если же я напишу именно константы на Си, то у меня в коде появятся операции умножения и т. п. Особенно весело будет если либа юзается на чем-то типа Тини13, и в проге сознательно избегается умножение/деление
Кто-нибудь знает причину ошибки:
Если я умножаю/делю/складываю дефайновские константы, то все эти операции делает препроцессор и в код ничего не идет. Если же я напишу именно константы на Си, то у меня в коде появятся операции умножения и т. п. Особенно весело будет если либа юзается на чем-то типа Тини13, и в проге сознательно избегается умножение/деление
Кто-нибудь знает причину ошибки:
Код: Выделить всё
Error[e27]: Entry "RC5_bit_cnt" in module LED_menu ( c:\firmware844\Debug\Obj\LED_menu.r90 ) redefined in module RC5 ( c:\firmware844\ Debug\Obj\RC5.r90 )

