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

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> Использование глобальных переменных
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
zltigo
сообщение Jan 9 2017, 19:22
Сообщение #2


Гуру
******

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



Цитата(demiurg1978 @ Jan 9 2017, 20:26) *
неоднократно слышал, что..

Ну так и спрашиваете там, где "неоднократно слышали".


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
desh
сообщение Jan 9 2017, 20:28
Сообщение #3


Частый гость
**

Группа: Свой
Сообщений: 113
Регистрация: 25-10-07
Из: Краснодар
Пользователь №: 31 725



Цитата(demiurg1978 @ Jan 9 2017, 21:26) *
Хочу вывести переменные из static в глобальные.
Ваши за и против.


Плохая практика. Программа быстро превращается в это
Go to the top of the page
 
+Quote Post
demiurg1978
сообщение Jan 9 2017, 20:33
Сообщение #4


Местный
***

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



Цитата(desh @ Jan 10 2017, 02:28) *
...

Скажу честно, с английским настолько не дружу.
Go to the top of the page
 
+Quote Post
zltigo
сообщение Jan 9 2017, 20:57
Сообщение #5


Гуру
******

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



Цитата(desh @ Jan 9 2017, 22:28) *
Плохая практика.

К чему эти глупые страшилки не по делу.



--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
aiwa
сообщение Jan 10 2017, 01:59
Сообщение #6


Местный
***

Группа: Участник
Сообщений: 301
Регистрация: 13-12-15
Из: Харьков
Пользователь №: 89 682



Цитата(demiurg1978 @ Jan 9 2017, 20:26) *
Хочу вывести переменные из static в глобальные.
Ваши за и против.

В Вашем случае, когда Вы сам себе хозяин это не имеет никакого значения, кроме личных предпочтений.
Само ключевое слово static появилось, при появлении второго программиста. Первый не хотел, чтобы другой использовал его глобальные переменные, вот и прятал их посредством статика.

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

Сообщение отредактировал aiwa - Jan 10 2017, 02:00
Go to the top of the page
 
+Quote Post
Dima_G
сообщение Jan 10 2017, 03:18
Сообщение #7


Местный
***

Группа: Свой
Сообщений: 279
Регистрация: 2-07-08
Из: Новосибирск
Пользователь №: 38 699



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


Смысла в простых get/set функциях, тупо устанавливающих значения локальных переменных нет. Проще использовать глобальные переменные.
get/set функции нужны в том случае, если производится какая-то дополнительная работа, помимо установки/возврата переменной. Например
Код
int set_age(int age)
{
  if (age>=0 && age <=100)
  {
    local_age = age;
    return 0;
  }

  perror("incorrect age!");
  return -1;
}


К вопросу о "много параметров", может есть смысл объединить их в структуры?
Go to the top of the page
 
+Quote Post
Непомнящий Евген...
сообщение Jan 10 2017, 06:30
Сообщение #8


Знающий
****

Группа: Свой
Сообщений: 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
Сообщение #9


Местный
***

Группа: Участник
Сообщений: 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, 07:33
Сообщение #10


Гуру
******

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



QUOTE (demiurg1978 @ Jan 10 2017, 09:11) *
Редактирование параметров в меню.
Собрать все параметры в структуру (наверняка это уже сделано для удобства сохранения/чтения да и вообще для повышения читабельности кода). Передавать в редактор указатель на эту структуру. Можно создавать копию этой структуры, передавать в редактор указатель на копию и переписывать обратно из копии в основную структуру только после того, как пользователь подтвердит, что он действительно в своем уме.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Непомнящий Евген...
сообщение Jan 10 2017, 08:17
Сообщение #11


Знающий
****

Группа: Свой
Сообщений: 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
Сообщение #12


Местный
***

Группа: Участник
Сообщений: 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
Сообщение #13


Знающий
****

Группа: Свой
Сообщений: 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
Сообщение #14


Местный
***

Группа: Участник
Сообщений: 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
scifi
сообщение Jan 11 2017, 08:31
Сообщение #15


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(aiwa @ Jan 10 2017, 04:59) *
Само ключевое слово static появилось, при появлении второго программиста. Первый не хотел, чтобы другой использовал его глобальные переменные, вот и прятал их посредством статика.

Неправда. static позволяет не засорять глобальное пространство имён. Скажем, если в программе два десятка модулей, и в каждом - десяток своих переменных, то это уже 200 глобальных переменных. Кому нужен этот бардак?

Цитата(demiurg1978 @ Jan 11 2017, 11:25) *
В си разве возможна такая запись: ".type" ?

Погуглите на тему "что нового в C99 по сравнению с C90". Там немало приятных плюшек добавилось.
Go to the top of the page
 
+Quote Post

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

 


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


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