Язык С: классы памяти
Классы памяти определяют область видимости и время жизни переменных и/или функций в программе, написанной на языке С. Они предшествуют типу, который модифицируют. В языке С различают четыре класса памяти:
- auto (автоматический);
- register (регистровый);
- static (статический);
- extern (внешний).
Класс памяти auto
Все локальные переменные по умолчанию принадлежат классу памяти auto , то есть являются автоматическими.
В приведенном примере две переменные определены в одном классе памяти. Использование auto возможно только внутри функций, т.е. для создания локальных переменных.
Класс памяти register
Класс памяти register используется для определения локальных переменных, которые должны храниться в регистре процессора, а не в оперативной памяти. Это означает, что переменная имеет максимальный размер, равный размеру регистра (обычно одно слово), и к ней не может быть применен унарный оператор & (из-за отсутствия места в памяти).
Класс register следует использовать только для переменных, требующих быстрого доступа, таких как счетчики. Следует также отметить, что определение register не означает, что переменная обязательно будет храниться в register . Это означает, что она МОЖЕТ храниться в register в зависимости от аппаратных ограничений и ограничений, связанных с выполнением программы.
Класс памяти static
Класс памяти static инструктирует компилятор поддерживать локальную переменную в течение всего времени жизни программы вместо того, чтобы создавать и уничтожать ее каждый раз, когда она входит и выходит из области видимости. Таким образом, статичность локальных переменных позволяет им сохранять свои значения между вызовами функций.
Модификатор static также может быть применен к глобальным переменным. В этом случае область видимости переменной ограничивается файлом, в котором она объявлена.
В программировании на языке С применение static к глобальной переменной приводит к тому, что только один экземпляр этого члена разделяется всеми объектами его класса:
Класс памяти extern
Класс памяти extern используется для того, чтобы дать ссылку на глобальную переменную, которая видна ВСЕМ файлам программы. Использование extern не может инициализировать переменную, однако указывает на имя переменной в месте памяти, определенное ранее.
При наличии нескольких файлов и определении глобальной переменной или функции, которая также будет использоваться в других файлах, extern применяется в другом файле для обеспечения ссылки на определенную переменную или функцию. Проще говоря, extern используется для объявления глобальной переменной или функции в другом файле.
Модификатор extern чаще всего применяется при наличии двух или более файлов, в которых используют одни и те же глобальные переменные или функции, как показано ниже.
C++. Классы памяти, которые могут объявляться при работе с классами и объектами классов. Ключевые слова register, extern, static, mutable
Объекты классов и классы могут объявляться с такими классами памяти:
- автоматический ( auto );
- регистровый ( register );
- внешний ( extern );
- статический ( static ).
- изменчивый ( mutable ).
Для каждого класса памяти определяется собственный спецификатор: auto , register , extern , static . Спецификаторы классов памяти определяют, как должна храниться переменная.
2. Каким образом используется класс памяти auto для классов? Пример
Класс памяти auto определяет автоматические переменные. По умолчанию, это локальные переменные, которые размещаются в стеке или внутренних регистрах процессора. «Время жизни» автоматической переменной ограничено временем выполнения функции (метода) или блока, в котором эта переменная определена. При обычном объявлении локального объекта класса или локальной переменной, например
эта переменная получает класс памяти auto .
Важно, чтобы после объявления, автоматические переменные были инициализированы. Поскольку, содержимое ячеек, которые выделены для этих переменных, неопределено.
Пример. Пусть имеем фрагмент функции, которая вычисляет сумму элементов массива A , состоящего из n целых чисел.
В функции MySum есть следующие автоматические переменные:
- A , n – формальные параметры являются также автоматическими переменными;
- sum , i – внутренние локальные переменные функции MySum .
Это также касается и объявления объекта класса. Если в методе (функции) объявлен объект класса, то этот объект имеет класс памяти auto .
Например. Пусть задан некоторый класс CMyClass .
Тогда, в некоторой функции MyFun() объект класса будет относиться к классу памяти auto (автоматический).
3. Каким образом используется класс памяти register ? Пример
Объект класса может объявляться с ключевым словом register . Задание ключевого слова register – это есть указание компилятору выделить для сохранения данных объекта не ячейке стека, а внутренние регистры процессора. Но это не означает, что компилятор обязательно разместит данные объекта в регистрах процессора. Кроме того, при указании register , компилятор может разместить данные в кэш-памяти. Основной целью объявления переменной (объекта) с ключевым словом register есть обеспечение максимально быстрого доступа к этой переменной и обработки этой переменной.
Пример. Пусть имеем объявление класса CMyClass .
Объект класса – это переменная типа этого класса. Поэтому, объект как и переменная может иметь класс памяти register .
4. Каким образом используется класс памяти extern ?
Если класс объявлен в одном модуле, а нужно объявить что этот класс есть внешним в другом модуле, тогда этот класс объявляется с ключевым словом extern . В этом случае не нужно дополнительно описывать внутреннюю реализацию данных и методов класса.
Например. Пусть дано два модуля «MyClass.h» и «Main.h» . В модуле «MyClass.h» реализовано объявление класса CMyClass . В модуле «Main.h» реализовано использование класса «MyClass.h» , который подключается извне с помощью директивы #include .
Чтобы использовать возможности внешнего класса CMyClass , в тексте модуля «Main.h» может быть добавлен следующий код
В этом случае, класс CMyClass считается внешним, то есть таким, который имеет класс памяти extern .
5. Каким образом используются статические объекты класса ( static )?
Объект класса может использоваться с ключевым словом static . В этом случае место для объекта выделяется в фиксированной области памяти. Работа со статическими объектами классов, которые объявлены с ключевым словом static ничем не отличается от работы с обычными статическими переменными.
Более подробно об использовании статических переменных в классах описывается в статье:
Пример. Пусть задан класс CMyCounter .
В классе объявлена общедоступная переменная d , конструктор и деструктор. Конструктор класса обнуляет начальное значение d .
Чтобы продемонстрировать использование статического объекта класса, нужно написать функцию, которая изменяет значения d относительно его предшествующего значения. В данном случае, реализована функция, которая увеличивает предшествующее значение d на 1. В функции объявляется статический объект класса CMyCounter .
Использование функции IncMyCounter() из другого программного кода демонстрирует тот факт, что статический объект не уничтожается после завершения вызова функции
Как видно из вышеприведенного фрагмента кода функция вызывается 3 раза. В последних двух вызовах учитывается предыдущее значение переменной d класса CMyCounter .
Если в функции IncMyCounter() объявить объект MC класса CMyCounter без ключевого слова static
это этот объект будет относиться к автоматическому ( auto ) классу памяти. В этом случае, при каждом вызове функции IncMyCounter()
для внутренней переменной d объекта класса CMyCounter , память будет снова выделяться. В результате чего, переменная d объекта MC будет:
- создаваться заново в нефиксированной области памяти при ее объявлении;
- инициализироваться с помощью конструктора класса ( d =0);
- уничтожаться при выходе из функции IncMyCounter() , поскольку объект класса MC объявлен как автоматический (класс памяти auto ).
6. В каких случаях используется класс памяти mutable (непостоянный) для объекта класса? Пример
Класс памяти mutable используется в объединении с так называемыми константными функциями (функциями, которые объявлены с ключевым словом const ).
Пример функции с модификатором const в классе CMyRadius
Если константная функция объявлена в классе, то эта функция не может изменять данные класса. Это есть основной целью объявления константной функции в классе – не допустить модификацию объекта, который ее вызовет. То есть, нижеследующую функцию в классе CMyRadius нельзя реализовывать:
Но, бывают случаи, когда нужно изменять значения данных с помощью константной функции.
Например, в случае, если данными класса может быть также сложный объект другого класса, в котором часть данных нужно изменить. Чтобы выйти из этой ситуации нужно использовать ключевое слово mutable при объявлении данных класса.
В нашем примере, чтобы можно было изменить значение переменной r с помощью константной функции, нужно ее объявить следующим образом
Такая запись означает, что значение переменной r в классе можно изменять с помощью константной функции. То есть, константную функцию Set() можно объявить в классе.
После изменений, текст класса следующий:
Использование класса в другом программном коде
Вышеприведенные утверждения справедливы только для native -классов. В среде CLR в managed -классах использование квалификаторов const и volatile не поддерживается.
C register keyword
In C register keyword suggests to the compiler that the current variable should be stored in a CPU register, rather than memory.
The idea
The central processor can hold a very small amount of data. This data is stored in places called registers. Data saved there, is accessed faster than data stored in memory. For that reason programs can load their most-frequently accessed data in the CPU registers.
This is the very idea of the register keyword in C. It tells the compiler that we will work frequently with the current variable and it should be stored for fast access. Note that this is only a “hint” to the compiler and it could ignore it(and most likely it will, but more about this in a minute).
C register – example in code
Restrictions
Register is a storage class specifier. We cannot use more than one storage class specifier for one variable.
Attempting to assign more than one storage class specifier will result in an error like " error: multiple storage classes in declaration specifiers "
This means that the following declarations are not correct:

Placing a variable in a processor register means that it does not have a memory address, because it is not in the memory. Therefore, in C, if you declare a variable with the register keyword, you cannot access its address with the & operator.
Even if the variable is placed in memory, the compiler should not allow you to access its address. You can use this to make sure that some variable will not be changed outside of its function.
The following code should not compile. In my case it returns a compile-time error " error: address of register variable ‘number’ requested "
If it compiles, it should give a warning and chances are the program will crash.
If you use a C++ compiler: Many people are using C++ compilers to compile their C programs. This is OK, but it could cause some confusion, because in C++ it is allowed to access the address of a register variable.
Usage in practice
Back in the days compilers were not very good at deciding when to use machine registers for variables. For that reason the C developers did this manually with the register keyword.
With time the compilers got smarter. They became better than us in deciding about variables storage. Today it is very unlikely that a developer will make a better decision about a register variable. In fact, most of the time you could only make things slower. That's why many compilers will always ignore the C register keyword when it comes to storage.
However, like we said earlier, you can use the C register keyword to make sure your variable will not be accessed by address and changed outside of the scope that you expect.
Register in C
Register is a keyword in C which suggests the system to use register as a memory for a variable instead of RAM. This accelerates the reading and writing of memory and enhances the overall performance. Note that using register does not gaurentee the use of system registers.
The time of memory access is as follows:
registers < cache < main memory (default) < secondary memory
Currently, most comiplers are optimized so that it is able to decide automatically which variable if stored in register will result in performance improvement.
Note that register is a reserved but unused keyword in C++. This is because C++ designers considered that compilers will be mature enough to tune this parameter better than developers in most cases.
Some key points regarding register in C:
- register only suggests using register memory
- We cannot get the memory location of such a variable
- We can get the size using sizeof()
Memory location
If we have declared a variable as a register, we cannot get the memory location.
Normal way of getting memory location of a variable is using the & operator like:
If i, the variable is declared as a register, it will give compile time error. For example:
Compile time error:
sizeof() of register variable
We can get the size of a register variable using sizeof() just like a normal variable like:
Complete C code example:
Comparing performance
Consider this code where we are considering registers and executing a loop:
It takes only 2 clock cycles. It uses registers.
If we avoid using registers, it will increase the time greatly. Consider this example:
Hence, we see that the execution time is significantly more when not using registers. Hence, in C programming, it is advised to use register for variables that will be used frequently.
Note that declaring register for all variables may not help as the system may not have so many registers available for use.
OpenGenus Foundation
The official account of OpenGenus IQ backed by GitHub, DigitalOcean and Discourse