реклама на сайте
подробности

 
 
> Использование глобальных переменных
demiurg1978
сообщение Jan 9 2017, 18:26
Сообщение #1


Местный
***

Группа: Участник
Сообщений: 333
Регистрация: 19-12-13
Из: Новосибирск
Пользователь №: 79 709



Хочу узнать мнение насчет использования глобальных переменных. Спрашиваю вот почему: неоднократно слышал, что использование глобальных переменных нужно максимально минимизировать. Откуда пошло это? В данный момент пишу проект. Свои проекты всегда стараюсь разделить на модули. static переменные. использование в других модулях посредством set_value (); get_value ();. Но в нынешнем проекте у меня много параметров. И если честно, я заколебался на каждую переменную писать свои функции установки и получения переменных. Хочу вывести переменные из static в глобальные.
Ваши за и против.

Сообщение отредактировал demiurg1978 - Jan 9 2017, 18:27
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
Непомнящий Евген...
сообщение Jan 10 2017, 06:30
Сообщение #2


Знающий
****

Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153



Цитата(demiurg1978 @ Jan 9 2017, 21:26) *
Хочу узнать мнение насчет использования глобальных переменных. Спрашиваю вот почему: неоднократно слышал, что использование глобальных переменных нужно максимально минимизировать. Откуда пошло это? В данный момент пишу проект. Свои проекты всегда стараюсь разделить на модули. static переменные. использование в других модулях посредством set_value (); get_value ();. Но в нынешнем проекте у меня много параметров. И если честно, я заколебался на каждую переменную писать свои функции установки и получения переменных. Хочу вывести переменные из static в глобальные.
Ваши за и против.


Проблема в связности. Если у вас все модули знают все про все другие модули - то связность высокая. Сложно понять, кто именно меняет данную переменную и по каким позывам. Сложно поменять алгоритм работы какого-то одного модуля - при этом придется менять все другие. Часто нельзя просто взять и записать в переменную значение - иногда это можно сделать только в определенных состояниях, иногда такая запись должна быть защищена критической секцией, иногда нужно проверить значение или выполнить какие-то действия до/после записи. Если все это размазать по разным модулям - очень легко где-то что-то забыть.

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

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

А вообще, дайте конкретный пример sm.gif По нему уже можно дать какие-то рекомендации


Цитата(zltigo @ Jan 9 2017, 23:57) *
К чему эти глупые страшилки не по делу.


Это не то, чтобы страшилки. Обычно, если в коде много GOTO или функции на тысячи строк или все "потроха" торчат наружу, то с ним что-то не так sm.gif Хотя конечно возможны какие-то ситуации, когда все это оправдано
Go to the top of the page
 
+Quote Post
demiurg1978
сообщение Jan 10 2017, 07:11
Сообщение #3


Местный
***

Группа: Участник
Сообщений: 333
Регистрация: 19-12-13
Из: Новосибирск
Пользователь №: 79 709



Цитата(Непомнящий Евгений @ Jan 10 2017, 12:30) *
А вообще, дайте конкретный пример sm.gif По нему уже можно дать какие-то рекомендации

Редактирование параметров в меню.
Go to the top of the page
 
+Quote Post
Непомнящий Евген...
сообщение Jan 10 2017, 08:17
Сообщение #4


Знающий
****

Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153



Цитата(demiurg1978 @ Jan 10 2017, 10:11) *
Редактирование параметров в меню.


Можно сделать так, как выше предложил Сергей.

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

Функция доступа получает специальный поток (откуда читается или куда пишется значение, значение может быть разных типов, а некоторые параметры имеют несколько значений) и требуемое действие (прочитать / записать / проверить допустимость значения). Возвращает успех или код ошибки.

И далее уже имея такой массив, несложно организовать редактирование / отображение параметров через меню или по интерфейсу. Можно сделать перебор всех параметров, их сохранение в какой-то промежуточный формат и т.п.
Go to the top of the page
 
+Quote Post
demiurg1978
сообщение Jan 10 2017, 11:24
Сообщение #5


Местный
***

Группа: Участник
Сообщений: 333
Регистрация: 19-12-13
Из: Новосибирск
Пользователь №: 79 709



Цитата(Непомнящий Евгений @ Jan 10 2017, 14:17) *
...

Спасибо всем за ответы.Народ, не поделитесь примерами? Я всегда старался посматривать, как делают другие. Брать лучшее из примеров. Не постесняюсь сказать, что многому научился как раз на форумах. На ответах на мои вопросы и приведенных примерах.

Сообщение отредактировал demiurg1978 - Jan 10 2017, 11:26
Go to the top of the page
 
+Quote Post
Непомнящий Евген...
сообщение Jan 11 2017, 06:05
Сообщение #6


Знающий
****

Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153



Цитата(demiurg1978 @ Jan 10 2017, 14:24) *
Спасибо всем за ответы.Народ, не поделитесь примерами? Я всегда старался посматривать, как делают другие. Брать лучшее из примеров. Не постесняюсь сказать, что многому научился как раз на форумах. На ответах на мои вопросы и приведенных примерах.


Готовый код я дать не могу - он писался для дяди, на плюсах и довольно запутан. Основная мысль, если переложить ее на Си, выглядит так

Интерфейс

CODE


enum ParamType {
paramInt,
paramUint,
paramFloat,
paramBytes,
};

// Поток для чтения и записи значений
// В простейшем случае это просто буфер, размер и тип значения в буфере
// Если параметр может иметь несколько значений, то придется усложнить (скажем сделать односвязный список таких структур)
// Если хочется иметь возможность делать произвольные действия (писать/читать сразу в формате протокола и т.п.), то тут должны быть указатели на функции
struct ParamStream {
void *buf;
uint16_t size;
ParamType type;
bool error; // произошла ошибка чтения/записи?
};

// это интерфейс к ParamStream, который позволяет читать/писать значение
// конкретная реализация зависит от вида ParamStream
uint8_t paramStream_readUI8(ParamStream *s) {
// конвертирует содержимое потока в uint8_t; если это невозможно - устанавливает s->error
}
uint16_t paramStream_readUI16(ParamStream *s);
...
uint16_t paramStream_readBytes(ParamStream *s, byte *buf, byte bufSize);

void paramStream_writeUI8(ParamStream *s, uint8_t v);
...
void paramStream_writeBytes(ParamStream *s, const byte *buf, byte bufSize);


enum ParamResult {
parres_OK,
parres_BadValue,
parres_NoParam,
parres_NoAction,
...
};

enum ParamAction {
paract_Get,
paract_Set,
paract_Check, // проверить значение на допустимость без установки - бывает полезно в меню
};

typedef ParamResult (*ParamAccessor)(ParamStream *s, ParamAction act);

struct ParamInfo {
uint16_t code;
ParamAccessor accessor;
};

/// Эта функция для пользователей данной системы. Она ищет в глобальном массиве ParamInfo параметр с данным кодом (бинарный поиск к примеру) и вызывает его accessor
ParamResult paramAccessor(uint16_t code, ParamStream *s, ParamAction act);



Использование

Код
// получить значение параметра 42
unsigned value;
ParamStream stream = {.buf=&value, .size = sizeof(value), .type=paramUint};
paramAccessor(42, &stream, paract_Get);

// установить значение параметра 55
byte buf[10] = {1, 2, 3};
ParamStream stream = {.buf=&buf, .size = sizeof(buf), .type=paramBytes};
paramAccessor(55, &stream, paract_Set);


Модуль 1

Код
int a, b;

// вычисляемый параметр только для чтения
ParamResult  param_42(ParamStream *s, ParamAction act) {
  switch(act) {
  case paract_Get: paramStream_writeUI8(s, a+b); return parres_OK;
  default: return parres_NoAction;
  }
}



Модуль 2

Код
byte buf[20];

// чтение/запись
ParamResult  param_55(ParamStream *s, ParamAction act) {
  switch(act) {
  case paract_Get: paramStream_writeBytes(s, buf, 20); return parres_OK;
  case paract_Set: paramStream_readBytes(s, buf, 20); return parres_OK;
  default: return parres_NoAction;
  }
}


Где-то нужен файл, который все функции доступа поместит в один массив (и в этот файл надо включить хидеры всех модулей с параметрами).

Код
ParamInfo paramInfo[] = {
  {42, param_42},
  {55, param_55},
  {0, 0} // терминатор


Теперь у нас есть обобщенный механизм доступа к параметру любого типа по коду. Дальше все в наших руках - можно написать адаптер для modbus / etc, доступ к произвольному параметру через меню, выплевывание всех параметров по интерфейсу и т.п.
Go to the top of the page
 
+Quote Post
demiurg1978
сообщение Jan 11 2017, 08:25
Сообщение #7


Местный
***

Группа: Участник
Сообщений: 333
Регистрация: 19-12-13
Из: Новосибирск
Пользователь №: 79 709



Цитата(Непомнящий Евгений @ Jan 11 2017, 12:05) *
Использование
Код
// получить значение параметра 42
unsigned value;
ParamStream stream = {.buf=&value, .size = sizeof(value), .type=paramUint};
paramAccessor(42, &stream, paract_Get);

// установить значение параметра 55
byte buf[10] = {1, 2, 3};
ParamStream stream = {.buf=&buf, .size = sizeof(buf), .type=paramBytes};
paramAccessor(55, &stream, paract_Set);

В си разве возможна такая запись: ".type" ?
Go to the top of the page
 
+Quote Post

Сообщений в этой теме
- demiurg1978   Использование глобальных переменных   Jan 9 2017, 18:26
- - zltigo   Цитата(demiurg1978 @ Jan 9 2017, 20:26) н...   Jan 9 2017, 19:22
- - desh   Цитата(demiurg1978 @ Jan 9 2017, 21:26) Х...   Jan 9 2017, 20:28
|- - demiurg1978   Цитата(desh @ Jan 10 2017, 02:28) ... Ска...   Jan 9 2017, 20:33
|- - zltigo   Цитата(desh @ Jan 9 2017, 22:28) Плохая п...   Jan 9 2017, 20:57
- - aiwa   Цитата(demiurg1978 @ Jan 9 2017, 20:26) Х...   Jan 10 2017, 01:59
- - Dima_G   Цитата(demiurg1978 @ Jan 10 2017, 01:26) ...   Jan 10 2017, 03:18
|- - Сергей Борщ   QUOTE (demiurg1978 @ Jan 10 2017, 09:11) ...   Jan 10 2017, 07:33
||- - k155la3   Цитата(Сергей Борщ @ Jan 10 2017, 10:33) ...   Jan 11 2017, 09:50
||- - zltigo   Цитата(k155la3 @ Jan 11 2017, 11:50) Позв...   Jan 11 2017, 11:31
|- - Сергей Борщ   QUOTE (demiurg1978 @ Jan 10 2017, 13:24) ...   Jan 11 2017, 12:52
|- - Непомнящий Евгений   Цитата(Сергей Борщ @ Jan 11 2017, 15:52) ...   Jan 11 2017, 13:25
||- - Сергей Борщ   QUOTE (Непомнящий Евгений @ Jan 11 2017, 15...   Jan 12 2017, 10:05
|- - Dog Pawlowa   Цитата(Сергей Борщ @ Jan 11 2017, 15:52) ...   Jan 14 2017, 16:29
- - scifi   Цитата(aiwa @ Jan 10 2017, 04:59) Само кл...   Jan 11 2017, 08:31
|- - demiurg1978   Хм... Всем спасибо. Некоторым - в который уже раз....   Jan 11 2017, 08:56
- - aiwa   Цитата(scifi @ Jan 11 2017, 10:31) Неправ...   Jan 12 2017, 12:39
|- - Сергей Борщ   QUOTE (aiwa @ Jan 12 2017, 14:39) Перемен...   Jan 14 2017, 10:53
|- - Непомнящий Евгений   Цитата(aiwa @ Jan 12 2017, 15:39) Ну бард...   Jan 16 2017, 05:14
- - Укушенный воблой   Цитата(demiurg1978 @ Jan 9 2017, 19:26) Х...   Jan 14 2017, 18:03
- - aiwa   Цитата(Сергей Борщ @ Jan 14 2017, 12:53) ...   Jan 16 2017, 08:26
|- - Непомнящий Евгений   Цитата(aiwa @ Jan 16 2017, 11:26) 7-кратн...   Jan 16 2017, 10:14
- - aiwa   Цитата(Непомнящий Евгений @ Jan 16 2017, 12...   Jan 17 2017, 02:54


Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 27th June 2025 - 18:04
Рейтинг@Mail.ru


Страница сгенерированна за 0.01444 секунд с 7
ELECTRONIX ©2004-2016