2016-10-15 2 views
3

Предположим, что у меня есть переменная counter. Если мне нужно:Метод предотвращения глобальных переменных в C

  • доступ и изменить переменную из многих мест в коде
  • убедитесь, что переменная модифицируется в «правильный» путь,

это решение адекватным, или есть ли более эффективные/чистые способы сделать это?

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, существует ошибка).

По существу, проблема с использованием функции для доступа к переменной заключается в том, что нет удовлетворительного способа сообщить вызывающему, что это значение неверно.

+0

Кроме того, это не очень безопасно для потоков, если вы когда-либо захотите использовать потоки. –

+1

Ваши примеры показывают только константу, переданную 'counter_access()'. Всегда ли значение всегда является константой? – chux

ответ

3

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

Чтобы сообщить, что что-то пошло не так, вы можете использовать некоторое значение «вне диапазона». В вашем случае диапазон счетчика 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 code\n"); 
} 
.... 
if (counter_get() == 100) { 
    printf("DONE!\n"); 
} 

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

Я добавил макрос counter_get(), чтобы пользователь не помнил, что добавление 0 имеет побочный эффект возврата текущего значения счетчика.

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

Внимательно посмотрите, что здесь мы пытаемся сопоставить объектно-ориентированный подход к инкапсулированию данных и операций. В этом случае мы реализовали (неявно) один экземпляр объекта (счетчика), который имеет два метода: один для изменения значения и один для получения значения.

Смежные вопросы