#c #global-variables
#c #глобальные переменные
Вопрос:
Предположим, у меня есть переменная counter
. Если мне нужно:
- доступ и изменение переменной из многих мест в коде
- убедитесь, что переменная изменена «правильным» способом,
является ли это решение адекватным или существуют более эффективные / более чистые способы сделать это?
int counter_access(int value) {
static int counter = 0;
if (value > 100) {
printf("there is a bug in the code");
return counter;
}
counter = value;
return counter;
}
А затем, когда мне нужно изменить переменную:
counter_access(10); /* increase counter by 10 */
counter_access(-2); /* decrease counter by 2 */
И когда мне нужно получить доступ к переменной:
if (counter_access(0) == 100) do_something();
Это решение кажется мне довольно запутанным. Однако я не могу придумать очень много хороших способов сделать это. Я мог бы использовать глобальные переменные (которые вызывают ошибки). Я мог бы передать адрес counter
функциям, которые в нем нуждаются, но это не гарантирует, что переменная не будет изменена неправильным образом (в приведенном выше примере, если counter
значение увеличивается более чем на 100, возникает ошибка).
По сути, проблема с использованием функции для доступа к переменной заключается в том, что нет удовлетворительного способа сообщить вызывающей стороне, что значение неверно.
Комментарии:
1. Кроме того, это не очень потокобезопасно, если вы когда-нибудь захотите использовать потоки.
2. Ваши примеры показывают только константу , переданную
counter_access()
. Всегда ли передаваемое значение является константой?
Ответ №1:
Использование одной функции для подобных вещей — хороший вариант для однопоточных программ, вам просто нужно правильно настроить все.
Чтобы сигнализировать о том, что что-то пошло не так, вы можете использовать некоторое значение «вне диапазона». В вашем случае диапазон счетчиков равен 0 .. 100.
У вас может быть что-то вроде:
#define COUNT_OVERFLOW -1
#define COUNT_UNDERFLOW -2
#define counter_get() counter_add(0)
int counter_add(int incr)
{
static int counter = 0;
int counter_temp;
counter_temp = counter incr;
if (counter_temp < 0) return COUNT_UNDERFLOW;
if (counte_temp > 100) return COUNT_OVERFLOW;
counter = counter_temp;
return counter;
}
Теперь, чтобы обнаружить ошибку, вы можете проверить, является ли возвращаемое значение <0:
cnt = counter_add(x);
if (cnt < 0) {
fprintf(stderr,"There is a bug in the coden");
}
....
if (counter_get() == 100) {
printf("DONE!n");
}
Обратите внимание, что значение counter
сохраняется, даже если есть ошибка. Кроме того, лучше не иметь таких функций, как ваши counter_access()
сообщения об ошибках печати, лучше проверить возвращаемое значение и заставить вызывающего его распечатать (если он так склонен).
Я добавил макрос counter_get()
, чтобы пользователь не помнил, что добавление 0 имеет побочный эффект возврата текущего значения счетчика.
Как упоминалось ранее, в более сложных случаях вам не следует использовать статические переменные (или, что эквивалентно, глобальные переменные). В этих случаях правильный способ — иметь a struct
, который устанавливается для каждого потока и сохраняет переменные, которые имеют отношение к этому состоянию потока. Вам нужно будет передать указатель на эту структуру и заставить counter_access()
функцию принимать ее в качестве параметра.
Присмотревшись, вы можете увидеть, что здесь мы пытаемся имитировать объектно-ориентированный подход к инкапсуляции данных и операций. В этом случае мы реализовали (неявно) единственный экземпляр объекта (счетчика), который имеет два метода: один для изменения значения и один для получения значения.