Модификаторы

Модификаторы можно разделить на четыре типа: модификаторы времени хранения, класса хранилища, размера и знаковости. Разберемся с ними по порядку.

Модификаторы времени хранения

По умолчанию все создаваемые переменные являются автоматическими — это значит, что область их видимости ограничена блоком, в котором они были объявлены (внутри функции или цикла). Для описания таких переменных имеется специальное слово — auto.

uint32_t a = 0;
auto uint32_t a = 0;

Данные записи идентичны, поэтому писать ключевое слово auto не обязательно. Более того, лучше его не использовать, так как в стандарте C++ данный модификатор обозначает другое.

Следующий модификатор, extern, позволяет создать внешнее связывание переменной, т.е. объявлена она может в одном файле, а использоваться в другом.

// photo_sensor.c
volatile uint32_t adc_data;
// main.c
extern uint32_t adc_data;

Следующий модификатор, static, позволяет объявить статические переменные. Создаются они до входа в main() и инициализируются нулями (если значение не задано).

static uint32_t value;

void main(void) {
    // ...
}

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

float get_temperature(uint8_t adc_value) {
    static const float temp_table[256] = { /* pre-calculated values */ };
    return temp_table[adc_value];
}

Массив temp_table будет создан и проинициализирован один раз.

Последний модификатор register советует компилятору разместить переменную в регистре ядра, чтобы ускорить работу с ней. Он является рудиментарным: современные компиляторы лучше знают, куда и какие переменные помещать. Однако если модификатор всё же используется, то стоит иметь в виду: так как переменная предположительно хранится в регистре ядра, получить ее адрес в памяти невозможно, а значит, невозможно и создать указатель на нее.

Модификаторы класса хранилища

Компилятор — довольно сложная программа, он знает о коде намного больше, чем разработчик, и способен «подправить» программиста, оптимизировав программу. Например, если компилятор не видит, где переменная меняет свое значение, он может для ускорения расчетов закэшировать ее значение, т.е. реальное значение в переменной по ее адресу будет отличаться от значения в кэше. Переменные, которые изменяются асинхронно к самой программе (например, в прерывании) следует создавать с использованием модификатора volatile.

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

// photo_sensor.c
volatile uint32_t adc_data;

Если предполагается, что переменная не должна менять свое значение (как иронично), то необходимо применить модификатор const.

const float pi = 3.1415926f;

Иногда, конечно, хочется округлить число Пи до 3 или 4, но теперь этого не позволит сделать компилятор. Этот модификатор может быть использован и в аргументе функции, но об этом позже.

Модификаторы размера

Из практических соображений в язык внесены дополнительные модификаторы для разграничения целых чисел с разным диапазоном значений (зависит от разрядности МК): short для 16-битного int, long для 32-битного и long long для 64-битного.

short int a = 0;
long int  b = 0;
long long c = 0L;

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

Модификаторы знаковости

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


Изменено:

Язык Си: 3 комментария

  1. >Вместо нуля может быть почти любой другой символ. Плюс и минус работают по-другому. Для выравнивания числа по по левому краю, а не по правому, перед числом нужно поставить знак минус.
    Лишне по

  2. Термин «регистр ядра» довольно специфичен. Звучит не привычно. А почему не использовать термин CPU или процессор или на худой конец микроконтроллер?

  3. Смысл статических переменных вне функции мне кажется не раскрыт. Такой модификатор делает переменную недоступной из других единиц трансляции. Т.е. не будет конфликта имен между разными .с файлами.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.