Что означает "статический" в C?

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

18 ответов


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

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

#include <stdio.h>

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, статический используется с глобальными переменными и функции для того чтобы установить их объем к содержащий файл. В локальных переменных, static используется для хранения переменной в статически выделенной памяти вместо автоматически выделенного память. Хотя язык не диктуют реализацию либо тип памяти, статически память обычно зарезервирована в данных сегмент программа при компиляции время автоматически выделяемая память обычно реализован как стек переходных вызовов.

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

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

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


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

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

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


короткий ответ ... Это зависит.

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

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

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


мульти-файл примере переменная

а.с:

#include <stdio.h>

/*
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 <stdio.h>

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 a.c -o a.o
gcc -c main.c -o main.o
gcc -o main main.o a.o

выход:

m()
i = 1
si = 1

m()
i = 2
si = 2

a()
i = 3
si = 1

a()
i = 4
si = 2

толкование

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

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

в программировании на C файлы часто используются для представления "классов" и static переменные представляют частные статические члены класса.

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

С99 проект N1256 6.7.1 "спецификаторы класса хранения" говорит, что static в "хранилище-класса описатель."

6.2.2 / 3 "связи идентификаторов" говорит static подразумевает internal linkage:

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

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

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

где " единица перевода-исходный файл после предварительной обработки.

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

С STB_LOCAL привязка.

если мы compile:

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 зачем вообще хранить статические переменные в таблице символов, когда нет оптимизации? Их можно использовать для чего угодно? Возможно, для отладки.

посмотреть также

попробуйте сами

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


Это зависит от:

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

функция вернет 1, 2, 3 и т. д. --- переменная в стеке.

а.с:

static int foo()
{
}

Это означает, что эта функция имеет область только в этом файле. Итак.c и b.c может иметь разные foo()s, и foo не подвергается воздействию общих объектов. Поэтому, если вы определили foo в a.c вы не могли получить к нему доступ из b.c или из любых других мест.

в большинстве библиотек C все" частные " функции статичны и большинство "общественные" - нет.


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

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

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

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

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

примечание: эти комментарии применимы только к C. В C++ применение "статических" методов класса действительно дает ключевому слову другое значение. Аналогично для расширения аргумента массива C99.


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

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

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

    static void foo() { ... }
    

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

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


Я ненавижу отвечать на старый вопрос, но я не думаю, что кто-то упомянул, как K&R объясняет это в разделе A4.1 of "the C Programming Language".

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

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

Питер Ван Дер Линден дает эти два значения в "экспертном программировании C":

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

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

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


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

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

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

   i++;
}

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


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

static int my_variable;

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

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

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


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

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


также отметить, что static может использоваться 4 различными способами.

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();
    }
}

вывод:

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, используемую в file2.c.

ссылки:

  1. http://en.wikipedia.org/wiki/Translation_unit_ (Программирование)
  2. http://en.wikipedia.org/wiki/Call_stack

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


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

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

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