объявить переменные в c как глобальные или инкапсулировать их и использовать геттер и сеттер

Я начал программировать на C и обычно ищу «лучшие практики» для структурирования своего кода.

Раньше я в основном использовал объектно-ориентированные языки, поэтому я начал перенимать некоторые практики из этих языков.

Мой конкретный вопрос: считается ли этот код «приемлемым» кодом C или я попадаю в общую ловушку для людей, пытающихся использовать инкапсуляцию в C?

// A.h 
void setValue(int);
int getValue();

// A.c 
#include "A.h"

int my_private_value;

void setValue(int v)
{   
  my_private_value = v;
}   

int getValue(void)
{   
  return my_private_value;
}

person Community    schedule 15.09.2012    source источник


Ответы (5)


Чтобы быть педантичным: в C нет глобальных переменных. Переменные имеют область действия, продолжительность хранения и связь. Ни для одного из них не существует «глобальной» квалификации.

Так что же происходит? Ваш

int my_private_value;

— это переменная с областью файла и внешней связьюдлительностью статического хранения). Этот тип связи означает, что на него можно ссылаться из любого другого файла, в области действия которого есть объявление extern int my_private_value. Чтобы избежать этого, переменная должна иметь внутреннюю связь. Чтобы объявить переменную с внутренней связью, используйте ключевое слово static:

static int my_private_value;

Итак, если вы хотите звучать как профессионал, всякий раз, когда вы испытываете искушение произнести «глобальную переменную», сделайте глубокий вдох и произнесите слова объект с областью действия файла и внешней связью. Это заставит вас блистать на всех собеседованиях C :-)

Если кто-то усомнится в вашей мудрости по поводу отсутствия «глобальных» переменных, вы даже можете доказать им это. Глобальные переменные находятся в области видимости везде, верно? Но в C область видимости объекта начинается только после его объявления. Отсутствие действительно глобальной переменной делает невозможным перенаправление ссылки на переменную, как в

 int *foo = &bar;   /* Doesn't work in C: bar is not (yet) in scope. */
 int bar = 42;

Это действительно работает, когда вы меняете местами две строки.

person Jens    schedule 15.09.2012

Единственное изменение, которое я бы внес в ваш код, это то, как определяется my_private_value. Я бы определил это как:

static int my_private_value;

Это предотвращает объявление внешними модулями кода extern int my_private_value; и последующий прямой доступ к нему.

person mah    schedule 15.09.2012

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

person Jon    schedule 15.09.2012

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

Что не является приемлемым в C, так это объявление:

int getValue();

который в C не является прототипом. Он объявляет функцию, которая может принимать неопределенное количество аргументов. Вместо этого используйте:

int getValue(void);
person Jens Gustedt    schedule 15.09.2012
comment
Хорошая точка зрения; Я исправил это для OP (который, вероятно, избалован C++ :-) - person Jens; 15.09.2012
comment
@Jens, эй, нет, это делает мой ответ почти бесполезным :( - person Jens Gustedt; 15.09.2012

Я видел, как это делалось в C раньше, и в этом нет ничего плохого, пока вы 1. не хотите быть потокобезопасным (чего вы на самом деле хотите) и не создаете глобальную переменную static и не выставлять его через заголовочный файл. Тем не менее, использование глобальных переменных является плохой практикой, и его следует избегать, если это возможно.

person Community    schedule 15.09.2012
comment
перевод: «В этом нет ничего плохого, за исключением всего того, что я собираюсь перечислить, что очень неправильно». ...хорошо, тогда. - person underscore_d; 26.08.2016