Вопросы по С/С++ (СИ)

Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Аватара пользователя
Psych
Опытный кот
Сообщения: 848
Зарегистрирован: Ср мар 02, 2011 07:47:39
Откуда: Уфа

Re: Вопросы по С/С++ (СИ)

Сообщение Psych »

Ну удалите эти сегменты тогда из линкера.
Реклама
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение WiseLord »

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
То есть сначала компилятор создаёт из перечисленных в его параметрах c-файлов o-файлы, а потом соединяет результаты в .elf.
Любой другой компилятор по сути делает то же самое - те файлы, которые перечислены в "проекте", просто перечисляются как аргументы командной строки исполняемого файла компилятора
Реклама
Аватара пользователя
Psych
Опытный кот
Сообщения: 848
Зарегистрирован: Ср мар 02, 2011 07:47:39
Откуда: Уфа

Re: Вопросы по С/С++ (СИ)

Сообщение Psych »

А причем здесь компиль, если это делает препроцессор??!!
Аватара пользователя
YS
Друг Кота
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение YS »

цепляю другие сишники проекта через include
:facepalm: :))) Бывает.
Но насколько помню, даже в институте сишники вроде цепляли.
У-у-у, институт - это точно не аргумент (чаще даже контр-аргумент, "послушай и делай наоборот"). Мы там тоже тако-о-ое в курсачах воротили... :)))

В общем, дело обстоит так. Включаются, разумеется, только .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: Вопросы по С/С++ (СИ)

Сообщение BCluster »

Сишники из makefile берутся. Когда вы в IAR добавляете в проект файл, он его автоматически в makefile записывает (у IAR не совсем классический makefile, но все же)
Реклама
Аватара пользователя
YS
Друг Кота
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение YS »

Кстати, показал эту тему своему другу, Ъ-программисту, выпускнику матмеха, дабы он проверил то объяснение, что я дал выше. Вот резюме профессионала:
m08pvv писал(а): ...
Короче, инклудить *.с - это как жрать суп вилкой
Можно, но не нужно - есть ложка
Да и вилку ещё мыть сложнее
Поэтому в армии дают только ложки
// ни ножей, ни вилок
По-моему, исчерпывающе. :)))
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Реклама
Аватара пользователя
Алексей FAV
Вымогатель припоя
Сообщения: 579
Зарегистрирован: Пн янв 01, 2007 22:27:34
Откуда: Оренбург
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение Алексей FAV »

а я все равно не понимаю, есть суп вилкой.не удобно но мне нравится. :)

P.S. простите я нечаянно :(
добрый, когда сплю. И не стоит уж так детализировать инженеры или радиолюбители. Для меня тот кто с удовольствием, как любитель или профессионал что то творит уже инженер, даже если без диплома...
Аватара пользователя
BCluster
Собутыльник Кота
Сообщения: 2512
Зарегистрирован: Пн апр 06, 2009 19:33:29
Откуда: Молдова, Кишинев
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение BCluster »

Простите меня, но я в УПОР НЕ ВТЫКАЮ, нафиг вообще инклюдить С файлы. Мне это даж в голову не приходило никогда :)
Аватара пользователя
ploop
Модератор
Сообщения: 13490
Зарегистрирован: Ср ноя 26, 2008 16:34:25
Откуда: Тамбовская обл.

Re: Вопросы по С/С++ (СИ)

Сообщение ploop »

Эх, хотел было расписать, да опоздал - всё уже рассказали :)

От себя посоветую поиграться со сборкой проекта без IDE. Вооружиться голым компилятором и блокнотом, написать программку в пару строк, собрать, добавить пару файлов - снова собрать. Очень помогает пониманию.
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение WiseLord »

Соглашусь, IDE часто способствует непониманию того, "как оно там внутри работает".
И хотя я, например, для редактирования C-шного кода использую QtCreator, но только по сути в качестве удобного текстового редактора с подсветкой синтаксиса, удобным древовидным списокм файлов проекта, автодополнением и возможностью рефакторинга кода. Но все правила компиляции прописаны вручную в Makefile.
Аватара пользователя
ploop
Модератор
Сообщения: 13490
Зарегистрирован: Ср ноя 26, 2008 16:34:25
Откуда: Тамбовская обл.

Re: Вопросы по С/С++ (СИ)

Сообщение ploop »

А QtCreator не сможет нормально сделать проект, если это не Qt-проект. Либо ковырять его придётся до посинения. Так что да, с ним проще вручную Makefile настроить.

А IDE замечательная.
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение WiseLord »

Сделать, возможно, и не может, но импортировать проект с имеющимся Makefile, может замечательно.
Только потом, если добавлять ещё .c файлы в него, надо в Makefile их дописывать самому.
Зато функции автодополняются и рефакторинг есть, а больше ничего и не надо.

А IDE замечательная...
Изображение
Аватара пользователя
aam
Собутыльник Кота
Сообщения: 2994
Зарегистрирован: Сб фев 20, 2010 14:00:12
Откуда: Москва

Re: Вопросы по С/С++ (СИ)

Сообщение aam »

Короче, это все круто, но тогда полная байда с дефайнами выходит.
Например, у меня фаылы используют какие-то константы типа "MCU_CLOCK" Определяется она естественно в начале проги. Но тогды выходит, что в библиотечный универсальный h-файл я должен включать "пользовательский" h-файл основной проги. Библиотека моя в данном случае, но в общем случае выходит бред - захочу использовать в другой проге - придется переписывать либу.

Файл main.h:

Код: Выделить всё

#define RCU_CLOCK    128
#define RCU_IR_PORT  PORTD
#define RCU_IR_PIN     2

#include "RC5.h" //подключаю библиотеку RC5

Библиотека протокола RC5 "RC5.h":

Код: Выделить всё

//на основе этих констант объявляются другие константы
#define PW_SHORT_MIN (889/RCU_CLOCK - 889/(4*RCU_CLOCK))
Файл RC5.c:

Код: Выделить всё

#include "RC5.h"
...
pin_st = !TST_PIN(RCU_IR_PORT,RCU_IR_PIN);
...
ну и т. п., т. е. используются указанные константы, хотя в файле  "RC5.h" не объявлены
В итоге компилер естесвтенно орет что не может найти RCU_CLOCK и т. д., но я не могу их объявить в файле "RC5.h", т. к. нарушу принцип "неприкосновенности" и универсальности библиотеки.

Т. е. собственно вопрос: а как тогда дефайнить настраиваемые параметры библиотек в пользовательской проге?
Аватара пользователя
Psych
Опытный кот
Сообщения: 848
Зарегистрирован: Ср мар 02, 2011 07:47:39
Откуда: Уфа

Re: Вопросы по С/С++ (СИ)

Сообщение Psych »

aam писал(а):но я не могу их объявить в файле "RC5.h", т. к. нарушу принцип "неприкосновенности" и универсальности библиотеки.
Неприкосновенный должен быть сишник. А вот h может быть вполне прикосновенный. Можно забацать отдельный хедер для таких настроек.
Аватара пользователя
aam
Собутыльник Кота
Сообщения: 2994
Зарегистрирован: Сб фев 20, 2010 14:00:12
Откуда: Москва

Re: Вопросы по С/С++ (СИ)

Сообщение aam »

А, типа так:
Файл RC5.h

Код: Выделить всё

/* Readme:
   Для работы с библиотекой необходимо создать файл Settings.h и в нем объявить константы RCU_CLOCK, RCU_PORT
*/
#include "settings.h"
...

При этом грубо говоря если я (юзер библиотеки) забыл создать файл settings.h, то препроцессор заорет что файл не найден и юзер залезет в H-файл и прочтет что надо его создать.

Т. е. это норм считается, не "вилкой суп"? :))

Так я и не понял преимуществ раздельной линковки... И почему инклюдить синики - через ж*у...
Ведь можно сишних цеплять к H в конце этого H и тогда на компилятор пойдет все одним куском.
Последний раз редактировалось aam Вт янв 21, 2014 11:29:49, всего редактировалось 1 раз.
Аватара пользователя
BCluster
Собутыльник Кота
Сообщения: 2512
Зарегистрирован: Пн апр 06, 2009 19:33:29
Откуда: Молдова, Кишинев
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение BCluster »

Так происходит из-за неправильной архитектуры проекта.
Варианта два:
1. Держать в каждом проекте свой main.h, который будет подключаться ко всем модулям. Тогда, не будет необходимости писать в каждом файле десяток инклюдов - только один.
2. Вместо дефайна сделать функцию инициализации, в которую передавать параметрами эти дефайны, а она в свою очередь проинициализирует какую-то переменную, которую потом и использовать в программе

У нас в проекте около 50 модулей, и есть файл main.h в котором определены все инклюды. А каждый сишник начинается с #include "main.h". Это требует только обертки от множественного инклюда, как было указано несколько постов назад.
Если хотите, чтобы библиотека использовалась другими людьми, да и вообще для мелких проектов, выберите второй способ.
Последний раз редактировалось BCluster Вт янв 21, 2014 11:33:22, всего редактировалось 1 раз.
Аватара пользователя
aam
Собутыльник Кота
Сообщения: 2994
Зарегистрирован: Сб фев 20, 2010 14:00:12
Откуда: Москва

Re: Вопросы по С/С++ (СИ)

Сообщение aam »

1-й вариант - собственно что я и сказал.
2-й вариант годится для компа. Но не для микроконтроллера! Т. к. это расточительное использование и без того малых ресурсов. А то так можно дожить до того, что диод от мега 128 зажигать будем :))
BCluster писал(а):Если хотите, чтобы библиотека использовалась другими людьми, да и вообще для мелких проектов, выберите второй способ.
А 1-й способ для чего тогда?
Я хочу для начала разобраться как НАДО писать проги и как НЕ НАДО. Проги я пишу для микроконтроллеров, как вы поняли))
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение WiseLord »

aam писал(а):Короче, это все круто, но тогда полная байда с дефайнами выходит.
Например, у меня фаылы используют какие-то константы типа "MCU_CLOCK" Определяется она естественно в начале проги.
Не знаю как насчёт других компиляторов, но у того же gcc (и avr-gcc, само собой) есть ключ D (http://www.rapidtables.com/code/linux/gcc/gcc-d.htm).

На картинке со скриншотом QtCreator выше видна, например, переменная F_CPU.
Компилятору она передаётся в виде avr-gcc .... -D F_CPU=16000000L
Это по сути равнозначно тому, что в каждый исходный файл проекта добавлена строка #define F_CPU=16000000L.
Поэтому, используя эту опцию, можно не заморачиваться о разных settings.h.
Аватара пользователя
ploop
Модератор
Сообщения: 13490
Зарегистрирован: Ср ноя 26, 2008 16:34:25
Откуда: Тамбовская обл.

Re: Вопросы по С/С++ (СИ)

Сообщение ploop »

aam
Используйте первый способ. Сделайте какой-нибудь global.h со всеми константами, и цепляйте куда надо.
Но правильным всё-таки является второй, с функциями инициализации. При грамотном написании и применении директив компилятора вы много не потеряете, но зато получите универсальность и совместимость. А хотите экономить - пишите всё в одном файле, а переносимость обеспечивайте с помощью копипаста :)
Аватара пользователя
aam
Собутыльник Кота
Сообщения: 2994
Зарегистрирован: Сб фев 20, 2010 14:00:12
Откуда: Москва

Re: Вопросы по С/С++ (СИ)

Сообщение aam »

Тут по мимо самой памяти для констант еще как бы такой момент:
Если я умножаю/делю/складываю дефайновские константы, то все эти операции делает препроцессор и в код ничего не идет. Если же я напишу именно константы на Си, то у меня в коде появятся операции умножения и т. п. Особенно весело будет если либа юзается на чем-то типа Тини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 )
Ответить

Вернуться в «Разные вопросы по МК»