Страница 183 из 386

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

Добавлено: Ср янв 22, 2014 02:38:37
unalex
aam писал(а):Короче, я так понял. Переменные я вс-таки должен объявлять ("unsigned char a;") именно в соответствующем сишнике (RC5.c). Тогда те из переменных, которые я хочу использовать другими модулями (файлами) проги, я должен дополнительно описать ("extern unsigned char a;") в h-файле. Те, которые сугубо личные и юзаются только внутри библиотеки - соответственно не описываю. Так?
операции с переменными
- объявление - указываем имя переменной и ее тип
- определение - выделяем для переменной память

переменная может иметь
- внешние связи - доступны из любой части программы(глобальные переменные)
- внутренние связи - доступны только внутри файла(глобальная со словом static)
- нет связей - локальная(видима только внутри функции и исчезающия при выходе из нее)

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

//main.c (или projectname.c, кому как нравится)
...
#include "module.h"
...
//объявление и определение глобальной переменной
//указываем имя и тип и выделяем память
//может использоваться другими файлами(имеет внешние связи)
int a;

//объявление и определение глобальной переменной
//указываем имя и тип и выделяем память
//не может использоваться другими файлами(имеет внутренние связи)
static int b;

int main()
{
	//объявление и определение локальной переменной
	//указываем имя и тип и выделяем память
	//доступна только в main() (не имеет связей)
	int c;

	c = blabla();
}

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

//module.h
#ifndef MODULE_H
#define MODULE_H

int blabla();

#endif

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

//module.c

//объявление(но не определение) глобальной переменной
//память для нее уже выделена в другом файле
//нужна чтобы получить доступ к переменной, определенной в другом файле
//а также чтоб не возникало ошибок при раздельной компиляции
extern int a;
...
	
int blabla()
{
	//объявление и определение локальной переменной
	//указываем имя и тип и выделяем память
	//доступна только в blabla() (не имеет связей)
	int d;
	...
	return d;
}

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

Добавлено: Ср янв 22, 2014 10:40:57
aam
ploop писал(а):Правильнее делать функции, принимающие и возвращающие значения или указатели на всяческие структуры. А сами эти, структуры например, описаны в h-файле, объявлены в с-файле.
Народ, не забывайте, мы не о компе говорим :)) И даже не о линуксе на плате))
В принципе, я все это понял - на компе я бы объявил класс на Си++ и не парился. Но когда речь идет о процах Тини и Мега (причем младших Мегах типа 8-й) какой может быть базар о каких-то доп. функциях get/set, когда каждый байт стараешься экономить?
Вообще, это все хорошо, но как на ПРАКТИКЕ ПРИНЯТО писать софт под эти процы? Понятно, что там классы никто не забабахивает.
Мне это интересно не только с точки зрения радиолюбителя, но и с точки зрения профессионала-разработчка МК-устройств, поэтому хочу привыкнуть правильно кодить контроллеры.
BCluster писал(а):то никакой гарантии что blabla будет виден из других модулей нет. В большинстве компиляторов виден. Но, например в IAR MSP430 это происходит через раз.
Ну вот и договорились... Т. е. через глобальные переменные мне не передать результатов?
Вот та же библиотека RC5 у меня хранит результат в глобальном Юнионе со структурой внутри. И код кнопки и устройства я дергаю в основной проге именно из этой структуры. Получается что я должен написать к ней функцию get, т. е. фактически метод доступа к компонентам класса выходит. И так на все??? Так никакой Тиньки не хватит. Не может быть чтоб их ТАК программировали! Но в то же время врят ли серьезные программисты кодят их с грубыми нарушениями правил.

Получается, что на модули можно разбивать только если очень приспичило, а выделить из основной проги модули типа "меню", "функция1", "функция2", которые тесно общаются между собой через общие глобальные переменные, не выйдет?
BCluster писал(а):сли англ позвоняет
Не позволяет :oops: Даташиты еще читаю, а долго осознанно читать книжку не смогу.
Я в институте Подбельсокго читал (не за один проход кстати :))) ) А кодили мы там на Борланд 3.11, т. е. для компа.
YS писал(а):Такая конфигурация вызовет ошибку
Вот она и вызвала :))

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

Добавлено: Ср янв 22, 2014 11:23:28
urry
а вы не экономьте каждый байт - эта экономия выходит всегда боком. Программа 100 раз переделывается под хотелки заказчика - и каждый раз переписывать код из-за чересчур сильных связей - замучаешься.
Что смущает в варианте объявить статиком переменную в одном файле и через гет оттуда забрать из другого файла ?

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

foo.c
static char  cRez=0;

char fnGetVar(void)
{
return cRez;
}

foo.h
extern char fnGetVar(void);
Что здесь такого страшного ?

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

Добавлено: Ср янв 22, 2014 12:08:21
Psych
aam писал(а):В принципе, я все это понял - на компе я бы объявил класс на Си++ и не парился. Но когда речь идет о процах Тини и Мега
Кстати на С++ никто вас не заставляет писать через ЖОПП. Я пишу на С++ для МК не используя классы, зато есть другие полезные плюшки.
aam писал(а): когда каждый байт стараешься экономить?
Нынче не так дорого байты стоят.
aam писал(а): поэтому хочу привыкнуть правильно кодить контроллеры.
Судя по вашим запросам вы хотите накатать супернезависимую библиотеку, которая делает всё без лишних телодвижений. А в мэйне хотите типа этого:

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

int main(){
sdelat_vse_pri_vse();
}
Не стоит тесно связанные с аппаратной частью функции (да еще и дефайны) забивать в модули. В мейне же должно быть что-нибудь. Бывает и большую по весу прогу на отдельные логические части не разобьешь, хотя конечно разбить можно всё что угодно---вот только надо ли это, если вы будете постоянно лазить по файлам и менять там что-то.

Есть программисты, а есть разработчики библиотек. Поизучайте как сделаны библотеки профами.
urry писал(а):Что смущает в варианте объявить статиком переменную в одном файле и через гет оттуда забрать из другого файла ?
Вот тебе и инкапсуляция, вот тебе и функция доступа :))

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

Добавлено: Ср янв 22, 2014 12:31:13
ploop
aam писал(а):Народ, не забывайте, мы не о компе говорим И даже не о линуксе на плате))
В принципе, я все это понял - на компе я бы объявил класс на Си++ и не парился. Но когда речь идет о процах Тини и Мега (причем младших Мегах типа 8-й) какой может быть базар о каких-то доп. функциях get/set, когда каждый байт стараешься экономить?
Да при чём тут ООП? Кроме, разве что, названий идентификаторов, начинающихся на set/get. Ну обзовите их vpendurit/poimet, чтобы не смущало :))) Передача указателя стандартная практика даже на ассемблере, только называют их напрямую - адресами.

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

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

Добавлено: Ср янв 22, 2014 13:35:33
aam
Psych писал(а):Судя по вашим запросам вы хотите накатать супернезависимую библиотеку, которая делает всё без лишних телодвижений. А в мэйне хотите типа этого
Нет, я всего-навсего хочу понять как ПРАВИЛЬНО кодить микроконтроллеры. При этом правильно без дури и с желанием иметь код минимального объема.
Или может тут дела обстоят как с начертанием схем, где ГОСТ читается кому как в голову взбредет? Ато у меня на работе была одна такая "чоткая" - так схемы после нее понять без пол литра водного раствора этанола невозможно :beer: Но возможности ГОСТа раскрыты почти полностью :)))

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

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

Добавлено: Ср янв 22, 2014 15:00:01
YS
Вообще, это все хорошо, но как на ПРАКТИКЕ ПРИНЯТО писать софт под эти процы? Понятно, что там классы никто не забабахивает.
На практике каждый дро пишет как хочет и как ему представляется наиболее красивым и правильным. В эмбеде (пока?) нет каких-то более-менее жестких специальных стандартов оформления кода, хотя ST и пытается пропихнуть свой (одна из причин того, что политику ST я недолюбливаю).

Кстати, ардуйня вполне использует классы и ООП. Код получается дичайше неэффективным - простая перекидывалка данных с Bluetooth-шилда на I2C с минимальными проверками занимала у меня больше 7 кБ на ардуино, но гуманитариям (а также, иногда, программистам-прикладникам) нравится, потому что при ардуиновом подходе требования к погружению в предметную область снижаются до нуля. Так что все зависит от того, чего мы хотим достичь. :)

ОК, давайте я раскажу как гляжу на это я. :)

1. В смысле принципов написания кода под встроенные системы следует руководствоваться правилами MISRA C. Может показаться, что их дофига, но на самом деле это не страшно - большинство из них просто концентрированный здравый смысл.

2. О модулях. Если проект немного сложнее мигалки, то я предпочитаю выносить в отдельные модули (.c + .h) логически законченные части программы. Например HAL, реализации интерфейсов, слои общения с пользователем и т.п.

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

3. Касаемо взаимодействия. До Get/Set я пока не дошел, хотя Init() частенько делаю. Для коммуникации с модулем я, бывает, применяю глобальные переменные с набором флагов. При этом стараюсь свести количество торчащих из модуля переменных к минимуму.
некоторые куски кода
Логически завершенные куски кода. :idea:

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

Добавлено: Ср янв 22, 2014 16:37:16
BCluster
aam писал(а):Ну вот и договорились... Т. е. через глобальные переменные мне не передать результатов?
Я этого не говорил. Я говорил о том, что объявить переменную надо в каждом .с, где она используется. Если она в .h объявлена как extern, то это будет одна и та же глобальная переменная.
aam писал(а):Народ, не забывайте, мы не о компе говорим И даже не о линуксе на плате))
Что вы прицепились к этой ерунде, и пишете ее в каждом посте. Кроилово каждого байта приводит к архитектурным ошибкам в проекте, и делает его совершенно непригодным для дальнейших модификаций. Я уже писал ранее, покажете код. Я думаю что там найдется куча вещей, которые можно оптимизировать без ущерба.
Вообще я стараюсь делать правильно сразу - если что-то где-то не влазит, тогда уже можно подумать о том, чтобы вставлять костыли. Но таких случаев раз два и обчелся.
Функции доступа к переменным занимают очень мало места, поэтому это не тот случай, где сильно съэкономится пространство.
aam писал(а):При этом правильно без дури и с желанием иметь код минимального объема.
Проведите эксперимент. С глобальными переменными и с функциями доступа. Уверен, результаты будут не такие, как вы ожидаете.
YS писал(а): В смысле принципов написания кода под встроенные системы следует руководствоваться правилами MISRA C.
Вот это хороший совет.
YS писал(а):ардуйня вполне использует классы и ООП
Я тоже использую классы и ООП в МК. Никто не умер, а в большом проекте очень хорошо помогает создать нормальную архитектуру. МК msp430 512kFLASH 32kRAM...
YS писал(а):простая перекидывалка данных с Bluetooth-шилда на I2C с минимальными проверками занимала у меня больше 7 кБ на ардуино
хотел бы глянуть, если можно, действительно жирновато :)
Я просто не вижу причин, почему ООП код должен быть намного больше по объему чем ПП-код. ООП оставляет вопросы по производительности, из-за полиморфного поведения объектов, в частности, и глубокого наследования. Но это совсем другая история.

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

Добавлено: Ср янв 22, 2014 16:41:37
YS
МК msp430 512kFLASH 32kRAM...
Мы-то говорим о совсем мелких МК. Когда столько памяти, так ООП это уже не такой грех... Да и проект у вас - явно не перекидывалка данных. :)
хотел бы глянуть, если можно, действительно жирновато
Напишу в ЛС.

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

Добавлено: Ср янв 22, 2014 17:18:44
BCluster
YS писал(а):Мы-то говорим о совсем мелких МК.
Я понимаю, я просто выразил точку зрения о том, что нормальный ООП незначительно больше по объему чем ПП-код :)

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

Добавлено: Чт янв 23, 2014 06:40:47
unalex
aam писал(а):Вот та же библиотека RC5 у меня хранит результат в глобальном Юнионе со структурой внутри. И код кнопки и устройства я дергаю в основной проге именно из этой структуры. Получается что я должен написать к ней функцию get, т. е. фактически метод доступа к компонентам класса выходит. И так на все??? Так никакой Тиньки не хватит
а с чего вы взяли что она должна хранить результат в глобальном пространстве?
сделайте его локальным, тратя на нее память, только когда она необходима

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

//main.c
#include "module.h"

int main (void)
{
	params firstCircuit, secondCircuit;//объявляем и выделяем память

	firstCircuit.voltage = 5;
	firstCircuit.current = 0.02;

	secondCircuit = change(firstCircuit);

	return 0;
}

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

//module.h

#ifndef MODULE_H_
#define MODULE_H_

typedef struct
{
	int voltage;
	double current;
}params;//объявляем, но память не резервируем

params change(params circuit);

#endif /* MODULE_H_ */

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

//module.cpp
#include "module.h"

params change(params circuit)
{
	circuit.voltage = 10;
	circuit.current = 0.01;
	return circuit;
}
заметьте, что память выделяется в main.c, а функция в module.c памяти не потребует, она лишь ссылается на область пямяти, выделенную в стеке при вызове этой функции

ктати никаких get не потребовалось

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

Добавлено: Чт янв 23, 2014 12:08:26
BCluster
unalex писал(а):ктати никаких get не потребовалось
А причем тут get?
Вообще речь шла о том, что не стоит использовать глобальные переменные. А модуль требует отдавать и получать некоторые значения. Ваш код не решает ни одной из этих задач. Кроме того, он не оптимален. Зачем передавать структуру по значению? Гораздо правильнее было бы передавать указатель на структуру. Тогда бы не пришлось хранить в стеке копию структуры.
Тогда бы все свелось к такому:

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

void change(params * circuit)
{
   circuit->voltage = 10;
   circuit->current = 0.01;  
}

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

change(secondCircuit);
Кстати, в вашем примере можно не передавать вообще ничего в качестве параметра, а просто определить в функции новую структуру. Что будет равносильно.

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

Добавлено: Чт янв 23, 2014 16:19:47
unalex
BCluster писал(а):Вообще речь шла о том, что не стоит использовать глобальные переменные
именно об этом я и вел речь

ну а пример выбран тривиальным, чтоб просто показать, что глобальных переменных не требуется, и никаких проблем с зависимостями и переопределениями в разных файлах не возникает, и естественно обратив внимание на тот факт что расходы памяти в таком случае не будут огромными, чего так боится коллега

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

Добавлено: Чт янв 23, 2014 21:22:42
aam
Глянул DATA в своей проге - больше 100 байт! Может как раз из-за глобальных переменных?)

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

Добавлено: Чт янв 23, 2014 21:48:24
BCluster
Вероятнее всего так. Вы ж не хотите показать, что за гениальность ваяете :)))
У нас сейчас проект на МК у которого 256кБ флэш, и 2(!!!) кБ ОЗУ :) Вот там мда ) Если учесть что флэш под завязку забит.
В принципе все решается методом искусственного хипа, если кому будет интересно - расскажу

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

Добавлено: Чт янв 23, 2014 22:04:28
aam
BCluster писал(а):В принципе все решается методом искусственного хипа, если кому будет интересно - расскажу
Типа new/ freе ? Но в чем фишка?

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

Добавлено: Пт янв 24, 2014 00:12:39
shads
Хотя я в Си без году неделя (тем более, после асма - Си трудновато дался) но все таки, какие никакие, а результаты есть.....
Так вот, как то один уважаемый человек мне рассказал, как он пишет на Си, тут - http://radiokot.ru/forum/viewtopic.php? ... д#p1338777
никаких глобальных переменных, все данные спрятаны внутри модулей, все обращения к ним - только через функции.
И хотя о совершенстве пока речи нет, но я именно в этом направлении все время иду, и очень рад что в самом начале освоения Си, получил пинок в правильном направлении .....
aam писал(а):Т. е. через глобальные переменные мне не передать результатов?
Именно!
Разбиваеш программу на модули. Я делаю например так (для примера DDS генератор):

Главный файл (вся высокоуровневая логика)
Глобальные переменные: Частота, режим работы, позиция курсора, байт флагов....ВСЕ! Остальные переменные со статиками внутри функций.
Отдельными модулями подключены LCD.h, AD9833.h, ENCODER.h

В каждом модуле - минимум глобальных переменных...

Общение с модулями идет только через обертки... (единственное где я обращаюсь напрямую из майна к глобальной области модуля - это буфер LCD дисплея)
Так вот, это только так кажется что общение через обертки - получается громоздко... На сам деле, компиль не глупый, так что там все минимально...

В результате имеем хоть и не С++ но тем не менее, довольно абстрактный код в майне, что делает программирование довольно комфортным, минимально трудоемким.
А модули максимально обособлены и легко подключаются к новым проектам...
aam писал(а):Получается что я должен написать к ней функцию get, т. е. фактически метод доступа к компонентам класса выходит. И так на все??? Так никакой Тиньки не хватит.
Если поставить цель максимально минимизировать, то тогда вам нужен асм... Си однозначно подразумевает лишние расходы ресурсов, но для их минимизации есть много нюансов, которые постигаются с опытом... тут например кое что обсуждалось http://radiokot.ru/forum/viewtopic.php?f=57&t=77142
По крайней мере уже нет смысла пихать чтото в мелкашку, т.к. более жирные МК стоят не дороже...

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

Добавлено: Пт янв 24, 2014 09:17:24
aam
shads писал(а):По крайней мере уже нет смысла пихать чтото в мелкашку, т.к. более жирные МК стоят не дороже...
А когда из 32-х ног Меги8 использовано только 10 - это типа круто и есть смысл? :))
Но либо я чего-то не понял, либо кодить не умею, но простейшая девайсина с пультом от телека и БЕЗ знаковых/сегментных индикаторов у меня в Тиню2313 не лезет.

К слову, делал зарядник для АА (там Мега32, 4 канала программных IBV-стабилизаторов тока, нефиговый алгоритм детектирования конца зарядки и ЖКИ 8х2 с нехилым меню) - заняло всего 25% флеша...


Скажите, а регистр флагов библиотеки тоже через get/set вытаскивать надо?
И вот если в пределах одного файла, скажем, основной программы, как без глобальных переменных я обойдусь? Ведь разные функции используют общие для всей программы переменные. Т. е. все равно от глобальных переменных никуда не деться.

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

Добавлено: Пт янв 24, 2014 10:16:08
menzoda
aam писал(а):И вот если в пределах одного файла, скажем, основной программы, как без глобальных переменных я обойдусь? Ведь разные функции используют общие для всей программы переменные. Т. е. все равно от глобальных переменных никуда не деться.
Они будут не глобальными, а "локальными" для модуля, и без них по понятным причинам не обойтись, если конечно модуль не представляет собой набор независимых функций (к примеру математических). Модуль на Си - это как-бы класс (возможно статический), статические переменные и функции модуля - как-бы приватные члены класса, в этом ничего плохого нет и избавляться от них не нужно.

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

Добавлено: Пт янв 24, 2014 10:16:29
BCluster
Во первых, деться от них можно. Для этого надо всего лишь передавать в качестве параметров в другие функции необходимые данные, либо использовать static внутри функций.
Во вторых, использование ВНУТРИ МОДУЛЯ некоторого количества static переменных вполне допустимо.
shads писал(а):В каждом модуле - минимум глобальных переменных...
Глобальная переменная это extern, видимая из всей программы. Статик-переменные внутри модуля это совсем другая песня. Тут речь идет о межмодульных взаимодействиях.

ЗЫ: Кстати, aam, вы в курсе как работают static-переменные внутри функций?