Что означает «статическое» значение в C?

Я видел слово static используемое в разных местах в коде C; это как статическая функция / class в C # (где реализация разделяется между объектами)?

  1. Статическая переменная внутри функции сохраняет свое значение между вызовами.
  2. Статическая глобальная переменная или функция «видятся» только в файле, объявленном в

(1) является тем более иностранной темой, если вы новичок, вот пример:

 #include  void foo() { int a = 10; static int sa = 10; a += 5; sa += 5; printf("a = %d, sa = %d\n", a, sa); } int main() { int i; for (i = 0; i < 10; ++i) foo(); } 

Это печатает:

 a = 15, sa = 15 a = 15, sa = 20 a = 15, sa = 25 a = 15, sa = 30 a = 15, sa = 35 a = 15, sa = 40 a = 15, sa = 45 a = 15, sa = 50 a = 15, sa = 55 a = 15, sa = 60 

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

(2) Широко используется как функция контроля доступа. Если у вас есть .c файл, реализующий некоторые функции, он обычно предоставляет пользователям только несколько «открытых» функций. Остальные его функции должны быть static , чтобы пользователь не смог получить к ним доступ. Это инкапсуляция, хорошая практика.

Цитата Википедии :

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

См. Здесь и здесь для более подробной информации.

И чтобы ответить на ваш второй вопрос, это не похоже на C #.

Однако в C ++ static также используется для определения атрибутов classа (разделяемых между всеми объектами одного и того же classа) и методов. В C нет classов, поэтому эта функция не имеет значения.

Существует еще одно использование, не описанное здесь, и это как часть объявления типа массива в качестве аргумента функции:

 int someFunction(char arg[static 10]) { ... } 

В этом контексте это указывает, что аргументы, переданные этой функции, должны быть массивом типа char с не менее чем 10 элементами в нем. Для получения дополнительной информации см. Мой вопрос здесь .

Короткий ответ … это зависит.

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

  2. Статические глобальные переменные не видны за пределами файла C, в котором они определены.

  3. Статические функции не видны вне файла C, в котором они определены.

Пример примера с несколькими файлами

ac :

 #include  /* Undefined behavior: already defined in main. Binutils 2.24 gives an error and refuses to link. https://stackoverflow.com/questions/27667277/why-does-borland-compile-with-multiple-definitions-of-same-object-in-different-c */ /*int i = 0;*/ /* Works in GCC as an extension: https://stackoverflow.com/a/3692486/895245 */ /*int i;*/ /* OK: extern. Will use the one in main. */ extern int i; /* OK: only visible to this file. */ static int si = 0; void a() { i++; si++; puts("a()"); printf("i = %d\n", i); printf("si = %d\n", si); puts(""); } 

main.c :

 #include  int i = 0; static int si = 0; void a(); void m() { i++; si++; puts("m()"); printf("i = %d\n", i); printf("si = %d\n", si); puts(""); } int main() { m(); m(); a(); a(); return 0; } 

Компиляция :

 gcc -c ac -o ao gcc -c main.c -o main.o gcc -o main main.o ao 

Выход :

 m() i = 1 si = 1 m() i = 2 si = 2 a() i = 3 si = 1 a() i = 4 si = 2 

интерпретация

  • для si есть две отдельные переменные: по одному для каждого файла
  • существует единая общая переменная для i

Как обычно, чем меньше область действия, тем лучше, поэтому всегда указывайте переменные static если сможете.

В программировании на C файлы часто используются для представления «classов», а static переменные представляют собой частные статические члены classа.

Какие стандарты говорят об этом

C99 N1256 draft 6.7.1 « Спецификаторы classа хранения» говорит, что static является «спецификатором classа хранения».

6.2.2 / 3 «Связи идентификаторов» говорит, что static подразумевают internal linkage :

Если объявление идентификатора области файла для объекта или функции содержит спецификатор classа хранения static, идентификатор имеет внутреннюю привязку.

и 6.2.2 / 2 говорит, что internal linkage ведет себя, как в нашем примере:

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

где «единица перевода» является исходным файлом после предварительной обработки.

Как GCC реализует его для ELF (Linux)?

С привязкой STB_LOCAL .

Если мы скомпилируем:

 int i = 0; static int si = 0; 

и разобрать таблицу символов:

 readelf -s main.o 

вывод содержит:

 Num: Value Size Type Bind Vis Ndx Name 5: 0000000000000004 4 OBJECT LOCAL DEFAULT 4 si 10: 0000000000000000 4 OBJECT GLOBAL DEFAULT 4 i 

поэтому привязка является единственной существенной разницей между ними. Value – это только их смещение в раздел .bss , поэтому мы ожидаем, что он будет отличаться.

STB_LOCAL зарегистрирован в спецификации ELF по адресу http://www.sco.com/developers/gabi/2003-12-17/ch4.symtab.html :

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

что делает его идеальным выбором для представления static .

Переменные без статики – STB_GLOBAL , а спецификация говорит:

Когда редактор ссылок объединяет несколько перемещаемых объектных файлов, он не допускает нескольких определений символов STB_GLOBAL с тем же именем.

который согласован с ошибками связи при множественных нестационарных определениях.

Если мы оптимизируем оптимизацию с помощью -O3 , символ si полностью удаляется из таблицы символов: его нельзя использовать извне. TODO, почему статические переменные в таблице символов вообще отсутствуют, когда нет оптимизации? Могут ли они использоваться для чего угодно? Может быть, для отладки.

Смотрите также

  • аналогично static функциям: https://stackoverflow.com/a/30319812/895245
  • сравнить static с extern , что делает «противоположное»: как использовать extern для обмена переменными между исходными файлами?

Попробуй сам

Пример для github для игры.

Это зависит:

 int foo() { static int x; return ++x; } 

Функция вернет 1, 2, 3 и т. Д. — переменная не находится в стеке.

переменный ток:

 static int foo() { } 

Это означает, что эта функция имеет область действия только в этом файле. Таким образом, переменные ac и bc могут иметь разные foo() s, а foo не подвергается совместным объектам. Поэтому, если вы определили foo in ac, вы не сможете получить к нему доступ из bc или из других мест.

В большинстве библиотек C все «частные» функции являются статическими, а большинство «публичных» – нет.

Люди продолжают говорить, что «статический» в C имеет два значения. Я предлагаю альтернативный способ просмотра, который дает ему одно значение:

  • Применение «статического» элемента к элементу заставляет элемент иметь два свойства: (a) он не отображается за пределами текущей области; (b) Это настойчиво.

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

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

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

ПРИМЕЧАНИЕ. Эти комментарии применимы только к C. В C ++ применение методов «static» to class по-настоящему дает ключевому слову другое значение. Аналогично для расширения аргумента массива C99.

static означает разные вещи в разных контекстах.

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

     void foo () { static int i = 0; printf("%d", i); i++ } 
  2. Другое использование static – это когда вы реализуете функцию или глобальную переменную в файле .c, но не хотите, чтобы ее символ был виден вне .obj сгенерированного файлом. например

     static void foo() { ... } 

Из Википедии:

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

Мне не нравится отвечать на старый вопрос, но я не думаю, что кто-то упомянул, как K & R объясняет это в разделе A4.1 «Язык программирования C».

Короче говоря, слово static используется с двумя значениями:

  1. Static – один из двух classов хранения (другой – автоматический). Статический объект сохраняет свое значение между вызовами. Объекты, объявленные вне всех блоков, всегда статичны и не могут быть автоматическими.
  2. Но, когда ключевое слово static (большой акцент на его использование в коде как ключевое слово) используется с объявлением, оно дает внутреннюю связь объекта, поэтому его можно использовать только в пределах этой единицы перевода. Но если ключевое слово используется в функции, оно меняет class хранения объекта (объект будет видимым только внутри этой функции). Противоположностью static является ключевое слово extern , которое дает объектную внешнюю связь.

Питер Ван Дер Линден дает эти два значения в «Expert C Programming»:

  • Внутри функции сохраняется ее значение между вызовами.
  • На уровне функции отображается только в этом файле.

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

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

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

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

 void procedure(void) { static int i = 0; i++; } 

значение «i» инициализируется до нуля при первом вызове процедуры, и значение сохраняется каждый последующий раз, когда вызывается процедура. если «i» были напечатаны, он выводит последовательность из 0, 1, 2, 3, …

Если вы объявите это в файле mytest.c:

 static int my_variable; 

Затем эту переменную можно увидеть только из этого файла. Переменная не может быть экспортирована нигде.

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

Статическая функция не может быть экспортирована извне файла. Таким образом, в файле * .c вы скрываете функции и переменные, если объявляете их статическими.

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

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

Также следует отметить, что static могут использоваться по-разному.

 to create permanent storage for local variables in a function. to specify internal linkage. to declare member functions that act like non-member functions. to create a single copy of a data member. 

Статическая переменная – это специальная переменная, которую вы можете использовать в функции, и она сохраняет данные между вызовами и не удаляет ее между вызовами. Например:

 void func(){ static int count; // If you don't declare its value, the value automatically initializes to zero printf("%d, ", count); count++; } void main(){ while(true){ func(); } } в void func(){ static int count; // If you don't declare its value, the value automatically initializes to zero printf("%d, ", count); count++; } void main(){ while(true){ func(); } } 

Выход:

0, 1, 2, 3, 4, 5, …

Статические переменные в C имеют время жизни программы.

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

Например:

 void function() { static int var = 1; var++; printf("%d", var); } int main() { function(); // Call 1 function(); // Call 2 } 

В вышеуказанной программе var хранится в сегменте данных. Его время жизни – это вся программа на С.

После вызова функции 1, var становится 2. После вызова функции 2, var становится 3.

Значение var не уничтожается между вызовами функций.

Если var имеет нестационарную и локальную переменную, она будет храниться в сегменте стека в программе C. Поскольку кадр стека функции разрушается после возвращения функции, значение var также уничтожается.

Инициализированные статические переменные сохраняются в сегменте данных программы C, тогда как неинициализированные хранятся в сегменте BSS.

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

Чтобы попробовать это:

file1.c

 static int x; int main() { printf("Accessing in same file%d", x): } 

file2.c

  extern int x; func() { printf("accessing in different file %d",x); // Not allowed, x has the file scope of file1.c } run gcc -c file1.c gcc -c file2.c 

Теперь попробуйте связать их, используя:

 gcc -o output file1.o file2.o 

Это даст ошибку компоновщика, так как x имеет область файла file1.c, и компоновщик не сможет разрешить ссылку на переменную x, используемую в файле2.c.

Рекомендации:

  1. http://en.wikipedia.org/wiki/Translation_unit_(programming)
  2. http://en.wikipedia.org/wiki/Call_stack

Статическое значение переменной сохраняется между различными вызовами функций, а область видимости ограничена локальным блоком, статический var всегда инициализирует значением 0

Есть 2 случая:

(1) Локальные переменные, объявленные static : выделены в сегменте данных вместо стека. Его значение сохраняется при повторном вызове функции.

(2) Глобальные переменные или функции, объявленные static : Невидимая внешняя единица компиляции (т.е. являются локальными символами в таблице символов во время связывания).

  • Статический анализ графика вызовов Java
  • Статические правила сериализации Java?
  • Создание объектов: конструкторы или статические заводские методы
  • Как обслуживать статические файлы из другого каталога, чем статический путь?
  • Можно ли заставить CMake создавать статическую и общую версию одной и той же библиотеки?
  • Статический вложенный class в Java, почему?
  • вызов нестатического метода в статическом методе в Java
  • Когда должен быть статический метод?
  • Зачем использовать статический вложенный интерфейс в Java?
  • статическая функция в C
  • Из статической библиотеки MinGW (.a) в статическую библиотеку Visual Studio (.lib)
  • Давайте будем гением компьютера.