Перейти к содержанию
    

Использование глобальных переменных

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

Ваши за и против.

Изменено пользователем demiurg1978

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

неоднократно слышал, что..

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Хочу вывести переменные из static в глобальные.

Ваши за и против.

 

Плохая практика. Программа быстро превращается в это

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Хочу вывести переменные из static в глобальные.

Ваши за и против.

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

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

 

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

Изменено пользователем aiwa

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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;
}

 

К вопросу о "много параметров", может есть смысл объединить их в структуры?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Ваши за и против.

 

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

 

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

 

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

 

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

 

 

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

 

Это не то, чтобы страшилки. Обычно, если в коде много GOTO или функции на тысячи строк или все "потроха" торчат наружу, то с ним что-то не так :) Хотя конечно возможны какие-то ситуации, когда все это оправдано

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Редактирование параметров в меню.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Редактирование параметров в меню.
Собрать все параметры в структуру (наверняка это уже сделано для удобства сохранения/чтения да и вообще для повышения читабельности кода). Передавать в редактор указатель на эту структуру. Можно создавать копию этой структуры, передавать в редактор указатель на копию и переписывать обратно из копии в основную структуру только после того, как пользователь подтвердит, что он действительно в своем уме.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Редактирование параметров в меню.

 

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

 

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

 

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

 

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

...

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

Изменено пользователем demiurg1978

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

 

Интерфейс

 


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, доступ к произвольному параметру через меню, выплевывание всех параметров по интерфейсу и т.п.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

// получить значение параметра 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" ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

 

В си разве возможна такая запись: ".type" ?

Погуглите на тему "что нового в C99 по сравнению с C90". Там немало приятных плюшек добавилось.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...