|
Немного стандарта написания программ на С, применительно к контроллерам |
|
|
|
Oct 26 2009, 08:20
|

Гуру
     
Группа: Свой
Сообщений: 2 113
Регистрация: 1-11-05
Пользователь №: 10 359

|
Всем привет. Разрабатываю программу для PIC24F. Необходимо более-менее придерживаться стандарта. У меня вопрос следующий... Обычно все переменные я объединяю в структуры, группирую по назначению Код typedef struct { alt_buttons* buttons; //ссылка на массив кнопок unsigned char max_key_num; //число кнопок в клавиатуре ....... unsigned char alpha; //прозрачность клавиатуры } alt_keyboard; Это удобно, т.к. список аргументов функций будет представлять собой не кучу всяких переменных, а лишь одну структуру (или несколько). Правильно, вроде как, считается создавать локальные переменные и передавать их затем в качестве аргумента. Например, в main: Цитата void main (void) { alt_keyboard keyboard;
system_init (&keyboard); Но вот необходимо обрабатывать прерывания. Как же быть там? Получается, нужно работать с глобальными переменными. Это плохо? Кто как поступает? Можно основные переменные (например, клавиатура, дисплей и т.п.) сделать глобальными и работать с ними из любой функции. Не?
--------------------
Быть. torizin-liteha@yandex.ru
|
|
|
|
2 страниц
1 2 >
|
 |
Ответов
(1 - 25)
|
Oct 26 2009, 08:35
|

Знающий
   
Группа: Свой
Сообщений: 943
Регистрация: 6-07-04
Из: Санкт-Петербург
Пользователь №: 274

|
Цитата(torik @ Oct 26 2009, 12:20)  Правильно, вроде как, считается создавать локальные переменные и передавать их затем в качестве аргумента. Например, в main: кем считается? первый раз такое слышу. Наоборот, если оптимизатор не отработает, то стеку будет расходоваться больше - к примеру, слово для локальной переменной и слово для передачи параметра (если через регистры все параметры передать не получится). Цитата(torik @ Oct 26 2009, 12:20)  Получается, нужно работать с глобальными переменными.Это плохо? Кто как поступает? в общем случае плохо, но иногда без этого никак, смело пользуйся
|
|
|
|
|
Oct 26 2009, 08:47
|

Беспросветный оптимист
     
Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646

|
Цитата(Alex B._ @ Oct 26 2009, 12:35)  в общем случае плохо, но иногда без этого никак, смело пользуйся А чем плохо? Переменная висит статически, в заранее известном адресе, существует всё время работы. И учитывать память проще, чем когда локальные переменные вываливаются на стек
--------------------
Программирование делится на системное и бессистемное. ©Моё :) — а для кого-то БГ — это Bill Gilbert =)
|
|
|
|
|
Oct 26 2009, 10:22
|
Местный
  
Группа: Свой
Сообщений: 279
Регистрация: 2-07-08
Из: Новосибирск
Пользователь №: 38 699

|
Цитата(torik @ Oct 26 2009, 11:20)  Я следую такому правилу - делать переменную глобальную только в том случае, когда без этого - никак (например, по другому никак не передать данные в/из обработчик прерываний и тд). Где-то вычитал правило и согласен с ним. Звучит как-то так: "Предпочитайте локальные переменные - глобальным, глобальные статические - просто глобальным" Цитата(MrYuran @ Oct 26 2009, 12:47)  А чем плохо? Переменная висит статически, в заранее известном адресе, существует всё время работы. 1. именно этим и плохо. Разово нужная переменная постоянно занимает память. 2. программы с глобальными переменными очень плохо читаются (ну это мое субъективное мнение) 3. глобальная - доступна всем желающим (во всей программе, либо в единице трансляции, если это - статик). Можно посадить трудноуловимые баги  . 4, Трудность переноса кода - если функция использует только локальные переменные, ее в общем случае можно просто "взять и выдернуть". Использующая глобальные переменные функция, потянет за собой хвост этих переменных...
|
|
|
|
|
Oct 26 2009, 10:59
|

Беспросветный оптимист
     
Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646

|
Цитата(Dima_G @ Oct 26 2009, 14:22)  1. Разово нужная переменная постоянно занимает память. Если разово, то согласен - локальные. Но бывают флаги/состояния, которые нужно хранить от вызова к вызову. Не забываем также, что речь идёт о программировании контроллеров, а не ПиСи Цитата 2. программы с глобальными переменными очень плохо читаются (ну это мое субъективное мнение) 3. глобальная - доступна всем желающим (во всей программе, либо в единице трансляции, если это - статик). Можно посадить трудноуловимые баги  . 4, Трудность переноса кода - если функция использует только локальные переменные, ее в общем случае можно просто "взять и выдернуть". Использующая глобальные переменные функция, потянет за собой хвост этих переменных... И что, предлагаете в мэйне организовать глобальную свалку переменных со всего проекта, а в каждую функцию передавать десяток параметров? Может, это и правильно с т.з. высоких материй (опять же применительно к PC), но в практической работе очень неудобно. Я в процессе эволюции пришёл к созданию максимально независимых модулей со своими глобальными и статическими переменными. Те переменные, которые надо видеть "снаружи" модуля, выношу extern-ом в h-файл модуля. А main в таком случае состоит из подключения соответствующих модулей через h-файлы, инициализации и быстрого суперцикла. "Взять и выдернуть" в таком случае можно не отдельную функцию, а модуль. Да и не надо его дёргать, просто подключить и использовать.
--------------------
Программирование делится на системное и бессистемное. ©Моё :) — а для кого-то БГ — это Bill Gilbert =)
|
|
|
|
|
Oct 26 2009, 11:20
|
Местный
  
Группа: Свой
Сообщений: 279
Регистрация: 2-07-08
Из: Новосибирск
Пользователь №: 38 699

|
Цитата(MrYuran @ Oct 26 2009, 14:59)  Не забываем также, что речь идёт о программировании контроллеров, а не ПиСи А в чем разница?  Цитата(MrYuran @ Oct 26 2009, 14:59)  И что, предлагаете в мэйне организовать глобальную свалку переменных со всего проекта, а в каждую функцию передавать десяток параметров? Может, это и правильно с т.з. высоких материй (опять же применительно к PC), но в практической работе очень неудобно. 1. Причем тут глобальная свалка? Не совсем пойму, что вы имеете в виду. Можете привести короткий пример? 2. Если в функцию передается больше 3х параметров (за редким исключением) - это повод задуматься о том, правильно ли разбили задачу на функции. Или возможно стоит объединить какие-то параметры в структуры. 3. Опять же - причем тут ПС? Или вы считаете, что хороший стиль на ПС и на МК отличается?
|
|
|
|
|
Oct 26 2009, 11:37
|
Местный
  
Группа: Свой
Сообщений: 279
Регистрация: 2-07-08
Из: Новосибирск
Пользователь №: 38 699

|
Цитата(xemul @ Oct 26 2009, 15:05)  Ну и компилятор может не переварить volatile у локальной переменной. В первый раз слышу.. На каком компиляторе у Вас вылезла такая проблема? Часто использовал локальные volatile переменные на многих платформах - gcc powerpc, gcc arm, gcc blackfin, VisualDSP, CodeComposer - никогда не имел с этим проблеммы  Цитата(MrYuran @ Oct 26 2009, 15:22)   Ну хотя бы в том, что иногда приходится считать (кило)байты и микросекунды. В особо запущенных случаях счёт идёт на такты... Ну я понимаю  Более того, иногда и для PC (кстати, а что в вашем понимании PC? Blackfin с uClinux в него входит? А PowerPC c Linux?  ) приходится сильно оптимизировать код. Хороший программист должен писать эффективный код, хоть на дохленьком PIC, хоть на 6 ядерном TMS64+
|
|
|
|
|
Oct 26 2009, 11:48
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(Dima_G @ Oct 26 2009, 14:37)  Часто использовал локальные volatile переменные на многих платформах - gcc powerpc, gcc arm, gcc blackfin, VisualDSP, CodeComposer - никогда не имел с этим проблеммы  Часто? Часто это скорее всего плохо, ибо мне известен только один случай, когда volatile применительно к локальной переменной имеет смысл, да и тот по сути есть вредительство. Не поделитесь примерами использования? Банальное любопытство мучает.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Oct 26 2009, 11:55
|
Местный
  
Группа: Свой
Сообщений: 279
Регистрация: 2-07-08
Из: Новосибирск
Пользователь №: 38 699

|
Цитата(zltigo @ Oct 26 2009, 15:48)  Часто? Часто это скорее всего плохо, ибо мне известен только один случай, когда volatile применительно к локальной переменной имеет смысл, да и тот по сути есть вредительство. Не поделитесь примерами использования? Банальное любопытство мучает. Инициализация периферии. Если этот регистр более нигде не нужен, использую его только локальной переменной Код class ClHardwareManager { static const DWORD INIT_REG_ADDR = 0x...; INT8 Init() { volatile DWORD* pdwInitReg_ = reinterpret_cast<volatile DWORD*>(INIT_REG_ADDR); *pdwInitReg_ = ... }
};
|
|
|
|
|
Oct 26 2009, 13:03
|
Местный
  
Группа: Свой
Сообщений: 279
Регистрация: 2-07-08
Из: Новосибирск
Пользователь №: 38 699

|
Цитата(ReAl @ Oct 26 2009, 15:57)  Да ну... Тут у Вас локальной переменной есть pdwInitReg_, но она ни на грамм не volatile. Указывает на volatile, но на НЕ локальную.  Ну да Перепутал маленько
|
|
|
|
|
Dec 4 2009, 02:35
|
self made
   
Группа: Свой
Сообщений: 855
Регистрация: 7-03-09
Из: Toronto, Canada
Пользователь №: 45 795

|
Цитата(Dima_G @ Oct 26 2009, 05:22)  1. именно этим и плохо. Разово нужная переменная постоянно занимает память. 2. программы с глобальными переменными очень плохо читаются (ну это мое субъективное мнение) 3. глобальная - доступна всем желающим (во всей программе, либо в единице трансляции, если это - статик). Можно посадить трудноуловимые баги  . 4, Трудность переноса кода - если функция использует только локальные переменные, ее в общем случае можно просто "взять и выдернуть". Использующая глобальные переменные функция, потянет за собой хвост этих переменных... размер пиковской памяти не настолько велик, чтобы говорить о трудности читания. Есть много нюансов о которых надо помнить при решении глобал-локал. Читаемость в общем случае будет в ущерб производительности, все зависит от того, насколько она вам критична.
Сообщение отредактировал ar__systems - Dec 4 2009, 02:35
|
|
|
|
|
Dec 14 2009, 06:35
|
Участник

Группа: Свой
Сообщений: 60
Регистрация: 8-11-05
Пользователь №: 10 602

|
Можно пользоваться указателями например вот так: Код typedef struct { alt_buttons* buttons; //ссылка на массив кнопок unsigned char max_key_num; //число кнопок в клавиатуре ....... unsigned char alpha; //прозрачность клавиатуры } alt_keyboard;
void* h_VarA;
void Proc1(void) { h_VarA->alpha = 123; }
main() { alt_keyboard keyboard;
system_init (&keyboard);
h_VarA = (void*)&keyboard;
Proc1(); } Но в этом случае надо следить за указателем. Чтоб к нему не было обращений, когда он еще не инициализирован или динамическая структура уже освобождена
|
|
|
|
|
Dec 14 2009, 07:40
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(alekseykoj @ Dec 14 2009, 08:35)  Можно пользоваться указателями Можно, но какой смысл? Заводим локальную переменную в main() и через указатель делаем ее как-бы глобальной. Какие преимущества это дает по сравнению с обычной глобальной переменной? Т.е. ради чего занимается лишняя память под указатель и ради чего мы вынуждаем процессор постоянно обращаться к структуре косвенно? Цитата(alekseykoj @ Dec 14 2009, 08:35)  например вот так: Вот так делать не нужно ни в коем случае. Вместо того, чтобы завести указатель на нужный тип и позволить компилятору контролировать ваши описки, вы заводите указатель на void * и вынуждены при каждом обращении вручную, принудительно приводить его к нужному типу. Компилятор не имеет возможности проверить, совместим ли объект, на который указывает указатель и тот тип, к которому вы его приводите методом грубой силы. Цитата(alekseykoj @ Dec 14 2009, 08:35)  Код void Proc1(void) { h_VarA->alpha = 123; } Не скомпилится. h_VarA - указатель на void Цитата(alekseykoj @ Dec 14 2009, 08:35)  Код h_VarA = (void*)&keyboard; Явное приведение лишнее. Любой не-cv (const и/или volatile) указатель приводится к void * неявно. P.S. используйте кнопку  на форме ввода для оформления кода.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Dec 14 2009, 09:56
|
Участник

Группа: Свой
Сообщений: 60
Регистрация: 8-11-05
Пользователь №: 10 602

|
Цитата Можно, но какой смысл? Заводим локальную переменную в main() и через указатель делаем ее как-бы глобальной. Какие преимущества это дает по сравнению с обычной глобальной переменной? Т.е. ради чего занимается лишняя память под указатель и ради чего мы вынуждаем процессор постоянно обращаться к структуре косвенно? Смысла ни какого. И так делать не надо. Просто если очень хочется... Глобальной она все равно не будет, т.к. эта переменная уничтожится при выходе из функции (если рассматриваем вариант не с функцией main). Вообще, для этих целей есть операторы new и delete. Которые позволяют контролировать выделяемые ресурсы в момент работы программы. Правильно будет так: Код typedef struct { alt_buttons* buttons; //ссылка на массив кнопок unsigned char max_key_num; //число кнопок в клавиатуре ....... unsigned char alpha; //прозрачность клавиатуры } alt_keyboard;
keyboard* h_VarA;
main() { // Выделяем ресурсы h_VarA = new alt_keyboard;
// Работаем с выделенными ресурсами....
// Освобождаем ресурсы delete h_VarA;
// Работаем дальше...
} Преимущества перед глобальной созданной статически в том, что я сам контролирую выделенные ресурсы и в любой момент могу освободить память для размещения другой структуры.
|
|
|
|
|
Dec 14 2009, 11:58
|
Участник

Группа: Свой
Сообщений: 60
Регистрация: 8-11-05
Пользователь №: 10 602

|
Извиняюсь  А так? Код typedef struct { alt_buttons* buttons; //ссылка на массив кнопок unsigned char max_key_num; //число кнопок в клавиатуре ....... unsigned char alpha; //прозрачность клавиатуры } alt_keyboard;
alt_keyboard* h_VarA;
main() { // Выделяем ресурсы h_VarA = malloc(sizeof(alt_keyboard));
// Работаем с выделенными ресурсами....
// Освобождаем ресурсы free(h_VarA);
// Работаем дальше...
}
|
|
|
|
|
Dec 14 2009, 14:08
|
Участник

Группа: Свой
Сообщений: 60
Регистрация: 8-11-05
Пользователь №: 10 602

|
Ну и делай ее глобальной. Ни каких "противопоказаний" нет. Единственное "противопоказание" следить за корректностью значения в переменной. (она же глобальная... Может быть изменена из нескольких модулей программы). Необходимо оформлять программу таким образом чтоб другие модули получали значение переменной или изменяли его с помощью функций того модуля которому "принадлежит" эта переменная. Тогда и проблемы с переносом модуля в другие программы отпадут сами собой.
|
|
|
|
|
Dec 14 2009, 14:24
|

Местный
  
Группа: Свой
Сообщений: 386
Регистрация: 1-12-05
Пользователь №: 11 639

|
Цитата(torik @ Dec 14 2009, 15:49)  Она может быть глобальная или нет. Согласен с alekseykoj - если Вам нужно глобальную переменную, так делайте ее. Если возможность обойтись без глобальной переменной лучше без нее обойтись В одном модуле .с- файла объявляете и инициализируте глобальную переменную а в .h файле этого же модуля объявляете ее как extern. И подключаете .h файл модуля к другим модулям где переменная используеться. Единственным "противопоказанием" может быть использование этой переменной в функции обработчике прерывания, в таком случае глобальной переменной нужно еще и volatile добавить при ее обявлении в с. файле модуля
|
|
|
|
|
Dec 14 2009, 14:37
|

Гуру
     
Группа: Свой
Сообщений: 2 113
Регистрация: 1-11-05
Пользователь №: 10 359

|
Цитата Единственное "противопоказание" следить за корректностью значения в переменной. (она же глобальная... Может быть изменена из нескольких модулей программы). Необходимо оформлять программу таким образом чтоб другие модули получали значение переменной или изменяли его с помощью функций того модуля которому "принадлежит" эта переменная. Тогда и проблемы с переносом модуля в другие программы отпадут сами собой. Цитата Единственным "противопоказанием" может быть использование этой переменной в функции обработчике прерывания, в таком случае глобальной переменной нужно еще и volatile добавить при ее обявлении в с. файле модуля Собственно с учетом всего этого и делаю. Уже давно, тема-то старенькая... Но вот чё-то заглянул.
--------------------
Быть. torizin-liteha@yandex.ru
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|