Одно из самых полезных ключевых слов в языке С и СPP static отвечает за распределение кода и данных в памяти.
Как следует из названия static определяет размещение кода или данных не на стеке или в куче, а именно в фиксированной области оперативной памяти static, причем расположение определяется на стадии компиляции и сборки программы.
Для лучшего понимания static смотрим сначала здесь как происходит сборка сpp файлов.
Другими словами static гарантирует однократное размещение в оперативной памяти переменной, функции, указателя.
Когда это становится выгодно? На самом деле это очень выгодно, если ваши данные однократно определяются и более не изменяются в процессе работы программы.
Ну например структура какой-то базы данных.
Применительно к классам, static переменные необходимо инициализировать особым образом вне класса (это про файл cpp).
И потом к этим переменным или функциям можно обращаться из других файлов через конструкцию класс::имя. Также смотрите: как определить константу глобально.
Главная идея собрать все неизменяюмые однократно определенные данные в static переменные/функции, обернуть это в класс (или в структуру) и пользоваться этими статическими данными из любого места программы.
Надо только подключить заголовочный файл этого класса и вуаля.
Отвлечения на тему контроллеров
Это только про язык С, не СРР.
При программировании микроконтроллеров static говорит компилятору/линковщику разместить данный объект в НЕ в стеке, а в сегменте BSS (Block Started by Symbol) , это просто оперативная память выделенная для данных вашей программе, размер которых заранее известен после компиляции/сборки.
BSS это сегмент памяти RAM , который фиксируется сразу при компиляции/линковке вашей программы.

К тому же синтаксически static гарантирует , что объект, объявленный с клюяевым словом static в конкретном файле blabalbla.c будет использоваться только в этом файле (blabalbla.c).
Это будет только локальный объект и в других файлах *.с будет не доступен . Таким образом в других файлах можно обзывать объекты таким же именем и конфликтов не будет. Это просто удобно.
Все эти варианты надо рассматривать на практических примерах. Начнем с простейшего :
глобальная переменная вне тела функции
Тут речь про static функцию не как метод класса, а просто обычную функцию.
static int COUNT=0;
void func1()
{
printf("");
//int COUNT=0;
printf("%d",COUNT );
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
printf("start main\n");
for (int i = 0; i < 10; i)
{
func1();
}
printf("\nend main\n");
return a.exec();
}
Когда используем static для глобальной переменной COUNT , то COUNT попадет в .bss сегмент.
Примечание: теперь из другого файла *.c до COUNT не достучитесь теперь никак (за исключением класс::имя_статик_переменной).
Когда COUNT без static, то COUNT попадет в кучу (heap).
Примечание: Теперь из другого файла *.с можно достучаться до COUNT через директиву extern.
локальная переменная в теле функции
#include
void func1()
{
printf("");
static int COUNT=0; // примечательно , что присваивание 0 происходит только один раз
//при инициализации программы , то есть в начале загрузки программы в память (.bss сегмент), еще до main
printf("%d",COUNT );
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
printf("start main\n");
for (int i = 0; i < 10; i)
{
func1();
}
printf("\nend main\n");
return a.exec();
}
Вывод:
start main
0123456789
end main
Если static не использовать в данном примере вывод будет таким:
start main
0000000000
end main
В данном варианте без static переменная COUNT создается на стеке для каждого вызова функции func1 заново (и ей присваивается 0 каждый раз заново).
Маленькая ржачка : никогда не называйте свои проекты в Qt словом static, добавьте еще хотя бы один символ.
статическая функция
#include
static void func1() //
{
static int COUNT123=0;
printf("%d",COUNT123 );
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
printf("start main\n");
for (int i = 0; i < 10; i)
{
func1();
}
printf("\nend main\n");
return a.exec();
}
На первый взгляд кроме того , что функцию func1 нельзя теперь вызвать из других cpp файлов вроде различий нет (что func1 со static , что без нее).
Есть большое и правильное ограничение в static функции. Это то, что в static функциях мы можем вызывать только другие static функции и присваивать значения другим только static переменным.
Но на самом деле в коде асемблерный код немного меняется. Без static так :
void func1()
{
0: 6b 58 01 00 imul $0x0,0x1(%eax),%ebx
4: 02 00 add (%eax),%al
static int COUNT123=0;
printf("%d",COUNT123 );
6: 00 00 add %al,(%eax)
6: secrel32 .debug_abbrev
8: 00 00 add %al,(%eax)
a: 04 01 add $0x1,%al
c: 47 inc %edi
d: 4e dec %esi
e: 55 push %ebp
f: 20 43 2b and %al,0x2b(%ebx)
12: 2b 20 sub (%eax),%esp
14: 34 2e xor $0x2e,%al
16: 34 2e xor $0x2e,%al
18: 30 00 xor %al,(%eax)
1a: 04 2e add $0x2e,%al
1c: 2e cs
1d: 5c pop %esp
1e: 73 74 jae 94 <.debug_info 0x94>
20: 61 popa
21: 74 69 je 8c <.debug_info 0x8c>
23: 63 5f 5c arpl %bx,0x5c(%edi)
}
А когда static func1 так:
static void func1()
{
0: 60 pusha / / !!!!
1: 58 pop %eax / / !!!!
2: 01 00 add %eax,(%eax) // и далее все тоже самое
4: 02 00 add (%eax),%al
static int COUNT123=0;
printf("%d",COUNT123 );
6: 00 00 add %al,(%eax)
6: secrel32 .debug_abbrev
8: 00 00 add %al,(%eax)
a: 04 01 add $0x1,%al
c: 47 inc %edi
d: 4e dec %esi
e: 55 push %ebp
f: 20 43 2b and %al,0x2b(%ebx)
12: 2b 20 sub (%eax),%esp
14: 34 2e xor $0x2e,%al
16: 34 2e xor $0x2e,%al
18: 30 00 xor %al,(%eax)
1a: 04 2e add $0x2e,%al
1c: 2e cs
1d: 5c pop %esp
1e: 73 74 jae 94 <.debug_info 0x94>
20: 61 popa
21: 74 69 je 8c <.debug_info 0x8c>
23: 63 5f 5c arpl %bx,0x5c(%edi)
}
Статик переменная в классах
С классами все намного интереснее. И это уже CPP
Допустим в классе есть статик переменная :
class class1{
public:
static int COUNT
Это объявление в файле class1.h .
Но этого не достаточно, в файле class1.c (или в любом другом файле *.с проекта) НАДО инициализировать статик переменную (глобально, над всеми функциями):
static int class1::COUNT=0
Если этого не будет , то проект может даже скомпилируется нормально, но когда дело дойдет непосредственно до работы с COUNT, то возникнут проблемы на этапе линковки.
В результате к переменной теперь COUNT можно обращаться из любого файла например таким образом:
class1::COUNT =2
И надо конечно понимать что переменная COUNT теперь всегда будет хранится в одном экземпляре , по одному адресу в оперативной памяти, не смотря на то , что самих классов class1 может быть создано несколько (но они создаются уже на стеке).
Когда статик переменные класса становятся реально необходимыми?
Есть такая функция например как
qInstallhandler
С помощью ее можно поменять обработчик событий.
В качестве параметра входит имя новой функции, которая у вас имеется (допустим назовем ее func1).
Но вот только func1 должна быть глобальной и лучше размещать ее в BSS.
А вам очень хочется , чтобы func1 была частью класса. Ведь класс удобен тем, что это кусок функционала , который удобно переносить из проекта в проект.
Класс созданный через new class1 в функции допустим func2 создается на стеке. При выходе из функции func2 класс class1 очищается.