2016-05-13 2 views
1

Я пишу библиотеку. Эта библиотека имеет функцию init(), которая инициализирует некоторые внутренние переменные. Эти переменные должны быть доступны снаружи, но только в режиме «только для чтения».Getter для переменной только для чтения в C

Поскольку я работаю над встроенным устройством, он слишком широк, чтобы иметь реальную функцию getter.

Что хорошее решение можно использовать, кроме этих двух из них (при условии, что они оба плохие решения):

Использование в inline поглотитель (где _internal_parameter не может быть static):

inline int get_parameter() { extern int _interal_parameter; return _internal_parameter; } 

Использование const (где переменная const не очень защищен):

// lib.c 
void init() { 
    *(int*)&parameter = get_value_for_parameter();   
} 

// lib.h 
extern const int parameter //!< initialized by init(); 
+0

Что именно не так с первым решением? – user4815162342

+0

Любой, кто читает файл заголовка, может осуществлять доступ и изменять '_internal_parameter', поскольку это не статическая переменная, ограниченная' lib.c'. – nowox

+1

Я думаю, что в этой ситуации практичность важна. Используйте inline с соответствующей документацией, предупреждающей о записи в '_interal_parameter'. Если пользователь все равно пишет, это их собственная ошибка. Если вызов одной функции может привести к неправильной работе, вы можете ожидать, по крайней мере, некоторого уровня компетентности от пользователей библиотеки. – user694733

ответ

2

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

Затем вы можете объявить не статическую функцию, которая возвращает значение либо по значению, либо по ссылке const (с помощью указателя const). Это заставит вас создать нормальную функцию. Inline не поможет, поскольку переменная скрыта в блоке компиляции.

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

Возможно, существует третий способ, и это будет объявление переменной static, а затем создание нестатического указателя const на переменную, которая будет экспонирована вне функции. В таком случае пользователь может по-прежнему потенциально модифицировать использование приведения.

+0

Последнее решение может быть тем, что я думаю :) – nowox

2

не имеет хороших способов инкапсуляции.

Реальная инкапсуляция может быть достигнута только путем внесения переменной static и доступа к ней с помощью не встроенного приемника. Это всегда будет возвращать копию указанной переменной.

Ваша вторая версия - это неопределенное поведение.

+0

Почему вторая версия не определена? – nowox

+0

1. Код не компилируется. В нем отсутствует определение. 2. Декларация и определение должны соответствовать. 3. Вы не можете отбросить const. 4. Строгое наложение. – Leandros

+1

Также можно достичь истинной частной инкапсуляции, используя «непрозрачный тип». Это также позволит вам использовать несколько экземпляров класса. (Даунсайд - это то, что вам нужно реализовать пул внутренней памяти для каждого класса, поскольку malloc не используется в правильно спроектированных встроенных системах.) – Lundin

1

Непонятно, почему было бы дорого использовать настоящую функцию геттера. Это скорее звучит так, как если бы ваш компилятор не делал вложения должным образом. Кроме того, неэффективность служебных вызовов функции часто сильно преувеличена, если вы не используете какую-то древнюю архитектуру MCU.

Оптимальным, конечно:

//lib.c 
int get parameter (void) 
{ 
    return parameter; 
} 

В качестве альтернативы, если вызов функции действительно слишком дорого, и вы не можете найти способ, чтобы исправить встраивание Поглотитель может вернуть const int*. Используйте локальную переменную-указатель в вызывающем абоненте, а затем вызывайте только один раз.

Обратите внимание, что использование int почти наверняка неверно в любой встроенной системе. Вместо этого используйте наименьший тип, который имеет смысл. Нужно ли его подписывать?На самом деле не имеет смысла говорить, что «мое приложение настолько критично в реальном времени, что я даже не могу вызвать функции», а затем сбрасываю в код код slappy int.

Следует избегать extern const, если переменная не является истинной переменной только для чтения (например, постоянной во флэш-памяти).

+0

Я работаю на 266 МГц процессоре, где цикл равен 3,75 нс. Наш рабочий цикл - 10us, что позволяет нам только 2600 инструкций по сборке. Вызов функции прерывает трубопровод и вызывает задержку около 14 инструкций. Встроенный геттер - это всего лишь 1 инструкция. Так что да, дорого использовать настоящую функцию геттера. – nowox

+0

Хороший вопрос о 'int'. Конечно, я использую 'int32_t' в этом случае. – nowox

+0

@nowox 2600 инструкций много! Хотя, как вы уже поняли себя, получить наилучшее решение - встраивание в работу. – Lundin

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