Например TDA7294

Форум РадиоКот • Просмотр темы - Структура исходника на Си
Форум РадиоКот
Здесь можно немножко помяукать :)





Текущее время: Ср апр 24, 2024 01:32:15

Часовой пояс: UTC + 3 часа


ПРЯМО СЕЙЧАС:



Начать новую тему Ответить на тему  [ Сообщений: 26 ]  1,  
Автор Сообщение
Не в сети
 Заголовок сообщения: Структура исходника на Си
СообщениеДобавлено: Вс июн 11, 2017 18:54:34 
Сверлит текстолит когтями
Аватар пользователя

Карма: 25
Рейтинг сообщений: 168
Зарегистрирован: Ср янв 29, 2014 08:41:31
Сообщений: 1231
Откуда: Баку
Рейтинг сообщения: 0
Предвижу очередную войнушку, но удержаться не могу, ибо хочу разобраться.

Для программирования на Си использую 2 среды: МПЛаб Х (понятно для чего) и Кейл (8051 и АРМ).
По первой у меня вопросов нет, т.к. она пропускает мою писанину, правильно или нет, не знаю, разберемся.
А вот Кайло ругается и потому прошу помощи у профи. Суть вопроса - в содержимом .c и .h файлов, т.е. что каждый из них должен содержать, а чего не должен. Сразу скажу, что проблема возникает в случае модульной структуры, когда есть main.c/.h, init.c/.h, lcd.с/.h и т.д. И если в Keil C51 я это как-то поборол, то Keil ARM мне не поддался.

После всей этой писанины сама проблема:
Цитата:
.\Objects\Flash_103C8.axf: Error: L6200E: Symbol SysTickCnt multiply defined (by lcd.o and main.o).

Ну и еще парочка в том же стиле, хотя модуль LCD системный таймер пока не использует, как и другие переменные, но которые он ругается.
Всякие ifndef стоят на месте, но не помогают.

В *.с файлах у меня только функции и инклюд на одноименный хедер. В хедер я заношу все описания функций, переменные, константы и инклюды на используемые модули. Как я подозреваю, этого делать нельзя, переменные вроде должны быть в *.с, но ведь это неудобно, файл захламляется. Да и МПЛаб против моего подхода ничего не имеет, возможно он слишком либеральный, но зато гибкий.

Что делать?

_________________
Каждый имеет право на свое личное ошибочное мнение.

У меня было тяжелое детство - я до 14 лет смотрел черно-белый телевизор.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Структура исходника на Си
СообщениеДобавлено: Вс июн 11, 2017 19:39:05 
Ум, честь и совесть. И скромность.
Аватар пользователя

Карма: 97
Рейтинг сообщений: 2058
Зарегистрирован: Чт дек 28, 2006 08:19:56
Сообщений: 18030
Откуда: Новочеркасск
Рейтинг сообщения: 4
Медали: 2
Получил миской по аватаре (1) Мявтор 3-й степени (1)
Zhuk72 писал(а):
Что делать?
Делать правильно :)
В заголовочнике не должно быть описания переменных без префикса extern. Т.е. если вам на самом деле нужна глобальная для всего многомодульного проекта переменная, ее можно описать в заголовочнике с этим префиксом, но сама она должна быть реализована в одном из модулей...
Инклюды в заголовочнике должны быть только на те другие заголовочники, без которых этот заголовочник не может быть реализован. То есть почти никогда их там быть не должно.
Допустимо в заголовочнике реализовывать inline-функции, в том числе и в виде макросов, но этот подход уже на гране "приличий".

_________________
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Структура исходника на Си
СообщениеДобавлено: Вс июн 11, 2017 19:39:18 
Друг Кота
Аватар пользователя

Карма: 1
Рейтинг сообщений: 157
Зарегистрирован: Пн окт 11, 2010 19:00:08
Сообщений: 3328
Рейтинг сообщения: 4
Если переменная должна быть доступна в других *.c файлах, ее нужно объявить в одном *.c файле где она используется, а в *.h файл добавить ее объявление с ключевым словом extern.


Вернуться наверх
 
PCBWay - всего $5 за 10 печатных плат, первый заказ для новых клиентов БЕСПЛАТЕН

Сборка печатных плат от $30 + БЕСПЛАТНАЯ доставка по всему миру + трафарет

Онлайн просмотровщик Gerber-файлов от PCBWay + Услуги 3D печати
Не в сети
 Заголовок сообщения: Re: Структура исходника на Си
СообщениеДобавлено: Вс июн 11, 2017 20:56:41 
Сверлит текстолит когтями
Аватар пользователя

Карма: 25
Рейтинг сообщений: 168
Зарегистрирован: Ср янв 29, 2014 08:41:31
Сообщений: 1231
Откуда: Баку
Рейтинг сообщения: 0
Так ведь это же неудобно.
И там описания, и там. Ведь намного нагляднее, если код в одном файле, а используемые им макросы, переменные и константы в другом.

Нельзя сделать неправильно так, чтобы получилось правильно?
:)
Некоторые компиляторы ведь это допускают и при этом все работает. Этот Си уже столько раз крутили под свои нужды, что еще раз выпрямить зигзаг - никто и не заметит, а потом всем понравится даже. Какая-такая причина тому, что переменные должны объявляться именно в *.с файле?

P.S. Сейчас попробую все-таки сделать правильно, которое ИМХО неправильно, потому что застрял.

Добавлено after 3 minutes 9 seconds:
P.P.S Скомпилировался.

Добавлено after 28 minutes 33 seconds:
Так, а если есть вот такая матрешка:
main.h
Код:
typedef struct
{
  unsigned hh: 8;
  unsigned mm: 8;
  unsigned ss: 8;
} hms;

main.c
Код:
...
hms time;
...

и мне нужно использовать структуру time еще и в init.c
Объявление ее как extern не помогает, не видит он ее.

_________________
Каждый имеет право на свое личное ошибочное мнение.

У меня было тяжелое детство - я до 14 лет смотрел черно-белый телевизор.


Вернуться наверх
 
Выбираем схему BMS для заряда литий-железофосфатных (LiFePO4) аккумуляторов

Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей.

Подробнее>>
Не в сети
 Заголовок сообщения: Re: Структура исходника на Си
СообщениеДобавлено: Вс июн 11, 2017 21:09:29 
Ум, честь и совесть. И скромность.
Аватар пользователя

Карма: 97
Рейтинг сообщений: 2058
Зарегистрирован: Чт дек 28, 2006 08:19:56
Сообщений: 18030
Откуда: Новочеркасск
Рейтинг сообщения: 0
Медали: 2
Получил миской по аватаре (1) Мявтор 3-й степени (1)
Zhuk72 писал(а):
Нельзя сделать неправильно так, чтобы получилось правильно?
нельзя
Zhuk72 писал(а):
Объявление ее как extern не помогает, не видит он ее.
тип у вас должен быть описан в заголовочнике, который проинклюден (проинклюжен?) во всех файлах, которые работают с этим типом.

в больших многомодульных проектах чаще всего должен быть "общий" заголовочник, в котором описаны главные типы и макросы для всего проекта - его надо подключать в каждом модуле проекта. а еще может быть заголовочник персонально для каждого модуля - их не надо инклюдить нигде, кроме их "родного"

Добавлено after 2 minutes 37 seconds:
я делаю обычно как-то так:
global.h - все макросы, типы, перечисления и т.п., общие для всего проекта, как правило, описывающие суть алгоритма
hardware.h - все, что касается описания периферии: алиасы портов, пинов, режимы АЦП и т.п.

потом к каждому исходнику его "родной" заголовочник.

первые два инклюдятся практически в каждом исходнике, остальные - где требуются.

_________________
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!


Вернуться наверх
 
Новый аккумулятор EVE серии PLM для GSM-трекеров, работающих в жёстких условиях (до -40°С)

Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре. Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств.

Подробнее>>
Не в сети
 Заголовок сообщения: Re: Структура исходника на Си
СообщениеДобавлено: Вс июн 11, 2017 21:10:36 
Сверлит текстолит когтями
Аватар пользователя

Карма: 25
Рейтинг сообщений: 168
Зарегистрирован: Ср янв 29, 2014 08:41:31
Сообщений: 1231
Откуда: Баку
Рейтинг сообщения: 0
Main.h включен в init.h

_________________
Каждый имеет право на свое личное ошибочное мнение.

У меня было тяжелое детство - я до 14 лет смотрел черно-белый телевизор.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Структура исходника на Си
СообщениеДобавлено: Вс июн 11, 2017 21:14:41 
Ум, честь и совесть. И скромность.
Аватар пользователя

Карма: 97
Рейтинг сообщений: 2058
Зарегистрирован: Чт дек 28, 2006 08:19:56
Сообщений: 18030
Откуда: Новочеркасск
Рейтинг сообщения: 0
Медали: 2
Получил миской по аватаре (1) Мявтор 3-й степени (1)
не надо инкюдить заголовочники внутри заголовочников - я уже говорил. это плохая практика.

вам в init.c нужна переменная time типа hms или сам тип hms? если тип - он должен быть виден при вашем подходе. если переменная - она должна быть в main.h описана с extern

_________________
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Структура исходника на Си
СообщениеДобавлено: Вс июн 11, 2017 22:14:17 
Сверлит текстолит когтями
Аватар пользователя

Карма: 25
Рейтинг сообщений: 168
Зарегистрирован: Ср янв 29, 2014 08:41:31
Сообщений: 1231
Откуда: Баку
Рейтинг сообщения: 0
Смешались в кучу кони, люди...

Убрал инклюды из заголовков, вписал их в *.с файлы.
Старые ошибки пропали, но вылезли новые, связанные с системными инклюдами.

_________________
Каждый имеет право на свое личное ошибочное мнение.

У меня было тяжелое детство - я до 14 лет смотрел черно-белый телевизор.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Структура исходника на Си
СообщениеДобавлено: Пн июн 12, 2017 06:52:02 
Ум, честь и совесть. И скромность.
Аватар пользователя

Карма: 97
Рейтинг сообщений: 2058
Зарегистрирован: Чт дек 28, 2006 08:19:56
Сообщений: 18030
Откуда: Новочеркасск
Рейтинг сообщения: 0
Медали: 2
Получил миской по аватаре (1) Мявтор 3-й степени (1)
ну с системными-то что не так может быть?

_________________
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Структура исходника на Си
СообщениеДобавлено: Пн июн 12, 2017 11:52:36 
Сверлит текстолит когтями
Аватар пользователя

Карма: 25
Рейтинг сообщений: 168
Зарегистрирован: Ср янв 29, 2014 08:41:31
Сообщений: 1231
Откуда: Баку
Рейтинг сообщения: 0
Что-то с типом данных в system_stm32_чегототам и еще в каком-то системном заголовке. Сейчас доеду до работы, буду разбираться на свежую голову.

Добавлено after 4 hours 31 minute 15 seconds:
Уфф, исправил наконец-то. Оказывается у меня в дисплейном модуле использовалась константа CMD, которая также присутствовала в stm32f10x.h в структуре определения SDIO. Ну и еще один дефайн был не к месту.
Остальное вроде распихал как бы по правилам. После этого все скомпилировалось.

_________________
Каждый имеет право на свое личное ошибочное мнение.

У меня было тяжелое детство - я до 14 лет смотрел черно-белый телевизор.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Структура исходника на Си
СообщениеДобавлено: Пт июн 16, 2017 22:56:38 
Друг Кота

Карма: 38
Рейтинг сообщений: 618
Зарегистрирован: Пн апр 06, 2015 11:01:53
Сообщений: 3092
Откуда: москва, уфа
Рейтинг сообщения: 0
Какая-такая причина тому, что переменные должны объявляться именно в *.с файле

логическая единица компиляции - C файл. Хидер - грубо говоря, просто описание "где-то есть вот такие штуки", он вообще говоря не компилируется в некоторый бинарник. Вот у нас переменная - не константа, а именно переменная, каковая собой представляет область памяти. Где мы ее будем выделять?


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Структура исходника на Си
СообщениеДобавлено: Сб июн 17, 2017 08:09:48 
Говорящий с текстолитом
Аватар пользователя

Карма: 33
Рейтинг сообщений: 148
Зарегистрирован: Вс июн 24, 2012 16:07:00
Сообщений: 1572
Откуда: Лен.Обл.
Рейтинг сообщения: 0
А зачем вам main.h? Файл main никогда никем не подключается (если конечно, не сделано извращение :) ). Наоборот, он подключает остальные файлы. Ему не нужен заголовок.
В заголовочных файлах сделаны объявления того, что вы с радостью отдадите другим модулям для использования. Так как модули компилируются индивидуально, то каждый модуль должен знать, что он собирается использовать из других модулей (не имея этого модуля во время компиляции!). Для этого и существуют заголовочные файлы.
В файлах модулей (*.c, *.cc, *.cpp) осуществляются объявления переменных. Для доступа к этим переменным в других файлах модулей эти переменные указываются с ключевым словом extern. Это знак компилятору, что эта переменная существует в другом модуле.

_________________
И день и ночь в пути...
Мои программки: https://github.com/da-nie
Мои публикации: https://habr.com/ru/users/da-nie/posts/
Мои видео: https://www.youtube.com/channel/UCUroi3 ... 52g/videos


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Структура исходника на Си
СообщениеДобавлено: Сб июн 17, 2017 14:02:39 
Потрогал лапой паяльник
Аватар пользователя

Карма: 20
Рейтинг сообщений: 121
Зарегистрирован: Вс янв 19, 2014 22:41:55
Сообщений: 353
Рейтинг сообщения: 3
Так ведь это же неудобно.
И там описания, и там. Ведь намного нагляднее, если код в одном файле, а используемые им макросы, переменные и константы в другом.

Это всё от непонимания сути происходящего процесса: 1) препроцессор склеивает из h-файлов и одного c-файла файл с кодом модуля; 2) компилятор компилит этот код модуля в соответствуюший ему объектный файл; 3) линкер собирает объектные файлы всех модулей проекта в программу - настраивает перекрёстные ссылки на функции и данные в разных модулях и устраняет неоднозначности [путём тыканья программистовым носом в место наличия оных]. Поставьте себя на место сначала компилятора а затем линкера - и вопросы почему так устроено снимутся. ;-) Компилятор не видит, что творится в других с-файлах, а линкер - не видит, что творится в голове программистов.
А XC8 может оказаться очень сильно неправ: если одноименная переменная но с разной функциональностью встречается в нескольких модулях проекта то линкер, сводящий все ссылки на неё в одно место, может оказаться как правым, так и не правым - в зависимости от мыслей в голове разработчика. А если таких головы на проекте две и более и мысли в них нагрузили эту переменную разной функциональностью - то очень скоро многие из них поймут как обиден "френдли фаер". Потому классический линкер и оставляет разрешение этих неоднозначностей на волю того, кто его запускает.

_________________
Одновременным нажатием LIGHT и POWER, РП Sangean ATS-909X (ver 1.29) превращается в ATS-909XR! ;-)


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Структура исходника на Си
СообщениеДобавлено: Сб июн 17, 2017 17:51:00 
Друг Кота
Аватар пользователя

Карма: 32
Рейтинг сообщений: 482
Зарегистрирован: Сб сен 10, 2011 17:46:25
Сообщений: 3832
Рейтинг сообщения: 0
линкер, сводящий все ссылки на неё в одно место, может оказаться как правым, так и не правым - в зависимости от мыслей в голове разработчика.

линкер GCC 6.1 для AVR сводит в одно место таки:
Изображение
обсуждалось http://electronix.ru/forum/lofiversion/ ... 98839.html


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Структура исходника на Си
СообщениеДобавлено: Сб июн 17, 2017 19:45:33 
Сверлит текстолит когтями
Аватар пользователя

Карма: 25
Рейтинг сообщений: 168
Зарегистрирован: Ср янв 29, 2014 08:41:31
Сообщений: 1231
Откуда: Баку
Рейтинг сообщения: 0
Во-первых, я уже разобрался со всем этим. Смирился, так сказать, с неизбежным и сделал по правилам. Все компилируется.

Во-вторых, возник вопрос к уважаемому Siarzhuk:
Цитата:
1) препроцессор склеивает из h-файлов и одного c-файла файл с кодом модуля;
Если он их склеивает, то не все ли равно, в каком из них двоих будут находится объявления переменных?
:)
Понятно, что все это правило, закон, "так положено" и прочее другое, с чем не поспоришь, но логически мне представляется более правильным, чтобы голый код находился в одном файле (*.с), а описание (объявление) использованных в нем элементов другом (*.h). В случае одинаковых по имени переменных в разных файлах линкер должен выводить предупреждение и останавливать сборку проекта.
А после того как все модули соберутся в одну длинную колбасу, за работу возьмется компилятор.

В-третьих, еще раз повторю: я не спорю, я уже смирился с существующим положением вещей, но моя личная логика и чувство комфорта дружно протестуют :)

_________________
Каждый имеет право на свое личное ошибочное мнение.

У меня было тяжелое детство - я до 14 лет смотрел черно-белый телевизор.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Структура исходника на Си
СообщениеДобавлено: Сб июн 17, 2017 19:55:14 
Говорящий с текстолитом
Аватар пользователя

Карма: 33
Рейтинг сообщений: 148
Зарегистрирован: Вс июн 24, 2012 16:07:00
Сообщений: 1572
Откуда: Лен.Обл.
Рейтинг сообщения: 0
Цитата:
Если он их склеивает, то не все ли равно, в каком из них двоих будут находится объявления переменных?


В h-файлах вообще не должны быть объявлены глобальные переменные. Потому как это описание, что содержит модуль, а не реализация. И одинаковые h-файлы могут подключаться в разные модули (скажем, функции для работы с UART нужны двум модулям), которые потом объединяются (и эти модули включаются в основной модуль).
Кстати, не забудьте в h-файле:

#ifndef MY_HEADER_FILE_H
#define MY_HEADER_FILE_H
...
текст h-файла
...
#endif

Иначе при сборке в вышеописанной ситуации получите ошибки компиляции - множественные определения (основной модуль несколько раз поставит в #include один и тот же h-файл).

Цитата:
А после того как все модули соберутся в одну длинную колбасу, за работу возьмется компилятор.


Модули компилируются индивидуально и не собираются в одну большую "колбасу"! В больших проектах это экономит уйму времени - перекомпиляция идёт только для изменённых модулей.
Но вы можете взять один *.c файл и кучу *.h в нём подключить. То есть, не использовать модульность. В этом случае компилируется один файл .c, а все h просто подставляются на место #include. И получается одна большая "колбаса". Но я так не советую делать - это не позволит индивидуально компилировать модули и считать из чем-то законченным.

Цитата:
В-третьих, еще раз повторю: я не спорю, я уже смирился с существующим положением вещей, но моя личная логика и чувство комфорта дружно протестуют


Вам следует взять книжку по Си (и Си++ на всякий случай - для обострения чувства протеста ;) ) и внимательно понять, как (и зачем) работает сборка проекта. :)

_________________
И день и ночь в пути...
Мои программки: https://github.com/da-nie
Мои публикации: https://habr.com/ru/users/da-nie/posts/
Мои видео: https://www.youtube.com/channel/UCUroi3 ... 52g/videos


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Структура исходника на Си
СообщениеДобавлено: Сб июн 17, 2017 20:44:57 
Друг Кота

Карма: 38
Рейтинг сообщений: 618
Зарегистрирован: Пн апр 06, 2015 11:01:53
Сообщений: 3092
Откуда: москва, уфа
Рейтинг сообщения: 0
Если он их склеивает, то не все ли равно, в каком из них двоих будут находится объявления переменных?

если у вас только два файла - все равно. Проблемы-то у вас начались как минимум с третьего)

Добавлено after 3 minutes 57 seconds:
Вам следует взять книжку по Си

если какое-то понимание уже есть - лучше стандарт почитать. Там есть много чего интересного, в частности, что компилятор по собственному усмотрению может делать с кодом)


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Структура исходника на Си
СообщениеДобавлено: Сб июн 17, 2017 21:06:49 
Потрогал лапой паяльник
Аватар пользователя

Карма: 20
Рейтинг сообщений: 121
Зарегистрирован: Вс янв 19, 2014 22:41:55
Сообщений: 353
Рейтинг сообщения: 0
[...] но логически мне представляется более правильным, чтобы голый код находился в одном файле (*.с), а описание (объявление) использованных в нем элементов другом (*.h). В случае одинаковых по имени переменных в разных файлах линкер должен выводить предупреждение и останавливать сборку проекта.

До слова "линкер" всё совершенно правильно. ;-) И тут маленькая проблемка - в дополнение к троице "препроцессор- компилер-линкер" появляется некая сущность - анализатор кода на перекрёстные ссылки. Какова его роль? и чем он отличается от компилятора, который и так уже который десяток лет занимается чем-то подобным не претендуя на глобальность.
А теперь преподношу под ваш мысленный взор проектик эдак на десяток тысяч модулей суммой на миллион строчек кода. Правлю кодестайл в самом занюханном углу дерева каталогов и прошу вас собрать проектик. :-) При нынешней модульной структуре никто и не заметит, что там в консоли проскочило, но если, как по-вашему, нужно будет анализировать весь миллион - "тады ой". И чем больше участников в проекте - тем больше времени потеряет проект. Лаконичный .h (АКА интерфейс модуля) позволяет выносить в глобальное пространство имён лишь то, что реально нужно знать окружающим - и не заставлять их пересобираться без особой на то необходимости.
А после того как все модули соберутся в одну длинную колбасу, за работу возьмется компилятор.

Да где-ж на вас памяти-то напасёшься?! ;-) Ну и все переменные, все функции, всех модулей в глобальном пространстве имён - судьбе этого компилятора может позавидовать только СССР-овский срочник у пулемёта в бункере на северном берегу Амура приснивший на посту начало китайского вторжения. ;-)

_________________
Одновременным нажатием LIGHT и POWER, РП Sangean ATS-909X (ver 1.29) превращается в ATS-909XR! ;-)


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Структура исходника на Си
СообщениеДобавлено: Сб июн 17, 2017 22:32:47 
Сверлит текстолит когтями
Аватар пользователя

Карма: 25
Рейтинг сообщений: 168
Зарегистрирован: Ср янв 29, 2014 08:41:31
Сообщений: 1231
Откуда: Баку
Рейтинг сообщения: 0
Кстати, не забудьте в h-файле:

#ifndef MY_HEADER_FILE_H
#define MY_HEADER_FILE_H
...
текст h-файла
...
#endif

Ну это я, конечно же, делаю, с тех самых пор, как начал делить программу на куски.
Вам следует взять книжку по Си (и Си++ на всякий случай - для обострения чувства протеста ;) ) и внимательно понять, как (и зачем) работает сборка проекта. :)

Учиться писанию на Си я начал натуральным методом тыка, относительно недавно, полтора года как, но с перерывами, по настроению. Просто взял свою же рабочую программу, написанную на асм, и начал переписывать на Си, поглядывая в список операторов. Потом доводил до рабочего состояния. Потом немного почитал, слегка поумнел и кое-что улучшил. А уже потом набрел на КиР, начал читать, но так и остановился где-то на середине :)

Siarzhuk писал(а):
А теперь преподношу под ваш мысленный взор проектик эдак на десяток тысяч модулей суммой на миллион строчек кода. Правлю кодестайл в самом занюханном углу дерева каталогов и прошу вас собрать проектик. :-)

Сдаёмсууу!
(с)

_________________
Каждый имеет право на свое личное ошибочное мнение.

У меня было тяжелое детство - я до 14 лет смотрел черно-белый телевизор.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Структура исходника на Си
СообщениеДобавлено: Вс июн 18, 2017 08:28:53 
Первый раз сказал Мяу!

Карма: 13
Рейтинг сообщений: 17
Зарегистрирован: Чт июн 15, 2017 10:40:31
Сообщений: 32
Откуда: Екатеринбург
Рейтинг сообщения: 1
Что то тут все у вас смешалось... Начать, наверное, стоит с общих моментов, без специфики С/С++. Сначала надо понять, что есть определение и есть описание. Описание не создает собственно переменной, а лишь описывает ее. Это еще называется декларированием. Сама переменная создается при определении. Вот например описание

Код:
struct smp_struct {
   int  a;
   char b;
};

real pi();

Тут ничего в памяти не размещается. А вот определение, основанное на этом описании

Код:
struct smp_str var;

real pi() {
   return 3.14;
}

Тут компилятор уже выделит память для переменной и функции. В заголовочных файлах (h, hpp, h++) обычно находятся описания типов, переменных, функций. Причем и для других языков программирования. Основная идея тут в облегчении написания программ состоящих из большого количества исходных файлов, разрабатываемых несколькими программистами, и тому подобного. Так в заголовочных файлах описаны системные вызовы и переменные, что бы не надо было вручную вписывать их в каждый файл. Включение (include) других заголовочных файлов из заголовочного файла (вложенное включение) вполне нормально и часто используется. Что бы избежать многократных определений и переопределений используют директивы препроцессора (в частности, условной компиляции), который собственно и работает с этими заголовочными файлами.

В модульном программировании, как и в функциональном, и модном сейчас структурном, дополнительно выделяется понятие модуля (может состоять из нескольких исходных файлов). Модуль имеет интерфейс и реализацию. Вот описание интерфейса, то есть того, как взаимодействовать с модулем, выносится в заголовочный файл (описание функций и глобальных переменных модуля). При этом кроме заголовочного файла с описанием интерфейса вполне себе могут существовать заголовочные файлы описывающие "внутренний мир" модуля. Они не нужны программисту использующему модуль, но нужны разработчику модуля.

Как происходит превращение исходных файлов в готовый двоичный файл... Сначала препроцессор обрабатывает исходный файл С обрабатывая директивы, в частности, заменяя include на содержимое собственно заголовочного файла. Естественно, отрабатываются и другие директивы, например, условной компиляции. На выходе получается С файл который передается уже собственно компилятору. Выходом компилятора является объектный файл. В нем уже нет текста, но есть описания программных секций, фрагменты двоичного кода, описания переменных (адрес, длина, имя секции). Линкер читает этот объектный файл и библиотечные файлы (наборы объектных модулей), собирает из секций кода и данных двоичный файл замещая созданные компилятором ссылки на переменные их фактическими адресами. Каждая секция кода и данных после компиляции содержит адреса и ссылки относительно начального адреса секции (на этом этапе 0) и только внутри секции. Линкер заменяет эти относительные адреса на фактические. При этом, линкер знает, где находятся все переменные и функции, так что может разобраться и с глобальными переменными.

Файл перекрестных ссылок содержит информацию о том, где какое имя (функция или переменная, не важно) определено, то есть, размещено в памяти, и где на это имя ссылаются (использование переменной, вызов функции, переход по адресу). Используется линкером в процессе сборки двоичного файла. Программисту может быть интересно, что бы узнать фактические адреса (включая системные переменные, не только в самой программе). Кроме того, используется для построения оверлейных структур (перекрытий) больших программ, которые нельзя загрузить в память целиком. Для микроконтроллеров, того же самого PIC, компилятор C, например XC, может разместить несколько переменных по одному и тому же адресу, если эти переменные не используются одновременно. Так что структуры перекрытий позволяют экономить и память кода, и память данных.

Извиняюсь за столь длинное и нудное описание основ, но автор, судя по всему, начинающий и для него важно понять, как это все устроено. Если перейти к конкретным советам и практике, то:

1. Заголовочный файл должен содержать только описания данных и кода. В нем не должно быть никаких определений! Исключением являются inline функции. Причем это верно и для С и для С++

2. Локальные и публичные переменные и функции модуля (файла) должные определяться в самом этот исходном файле модуля на основании описаний заголовочного файла, который подключается директивой include.

3. Вложенное использование директив include (включение одного заголовочного файла внутри другого) вполне допустимо и часто используется.

4. Для исключения переопределений и повторных описаний нужно использовать директивы условной компиляции.

5. Любая переменная должна быть описана только один раз (хотя некоторые компиляторы допускают повторные описания, при этом используя последнее) и определена только один раз. Если переменная должна быть доступна из других исходных файлов, то она описывается как глобальная. Для C любая переменная определенная вне тела функции считается глобальной, но в С++ может потребоваться дополнительный атрибут для членов классов. В других исходных файлах эта переменная должна быть описана как внешняя (extern), если требуется к ней доступ. Это все верно и для функций.

_________________
Мир вокруг нас разумен настолько, насколько разумны мы сами. Профессионал не обязательно говорит умные слова, но зная самые глубины, способен объяснить их любому "на пальцах".


Вернуться наверх
 
Показать сообщения за:  Сортировать по:  Вернуться наверх
Начать новую тему Ответить на тему  [ Сообщений: 26 ]  1,  

Часовой пояс: UTC + 3 часа


Кто сейчас на форуме

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 23


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
Русская поддержка phpBB
Extended by Karma MOD © 2007—2012 m157y
Extended by Topic Tags MOD © 2012 m157y