O que significa “estático” em C?

Eu vi a palavra static usada em diferentes lugares no código C; Isso é como uma function estática / class em c # (onde a implementação é compartilhada entre objects)?

  1. Uma variável estática dentro de uma function mantém seu valor entre invocações.
  2. Uma variável global estática ou uma function é “vista” apenas no arquivo declarado em

(1) é o tópico mais estrangeiro se você é um novato, então aqui está um exemplo:

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

Isso imprime:

 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 

Isso é útil para casos em que uma function precisa manter algum estado entre invocações e você não deseja usar variables ​​globais. Cuidado, no entanto, esse recurso deve ser usado com muita parcimônia - faz com que seu código não seja thread-safe e mais difícil de entender.

(2) É amplamente usado como um recurso de "controle de access". Se você tiver um arquivo .c implementando alguma funcionalidade, ele geralmente expõe apenas algumas funções "públicas" aos usuários. O restante de suas funções deve ficar static , para que o usuário não possa acessá-las. Isso é encapsulamento, uma boa prática.

Citando a Wikipédia :

Na linguagem de programação C, estática é usada com variables ​​globais e funções para definir seu escopo para o arquivo contido. Em variables ​​locais, estática é usada para armazenar a variável na memory alocada estaticamente em vez da memory alocada automaticamente. Enquanto a linguagem não determina a implementação de qualquer tipo de memory, a memory alocada estaticamente é normalmente reservada no segmento de dados do programa em tempo de compilation, enquanto a memory alocada automaticamente é normalmente implementada como uma pilha de chamadas temporária.

Veja aqui e aqui para mais detalhes.

E para responder sua segunda pergunta, não é como em C #.

Em C ++, no entanto, static também é usado para definir atributos de class (compartilhados entre todos os objects da mesma class) e methods. Em C não há classs, portanto, esse recurso é irrelevante.

Há mais um uso não coberto aqui, e isso é como parte de uma declaração de tipo de matriz como um argumento para uma function:

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

Nesse contexto, isso especifica que os argumentos passados ​​para essa function devem ser uma matriz do tipo char com pelo menos 10 elementos nela. Para mais informações, veja a minha pergunta aqui .

Resposta curta … depende.

  1. Variáveis ​​locais definidas estáticas não perdem seu valor entre as chamadas de function. Em outras palavras, elas são variables ​​globais, mas com escopo definido para a function local em que estão definidas.

  2. Variáveis ​​globais estáticas não são visíveis fora do arquivo C em que estão definidas.

  3. As funções estáticas não são visíveis fora do arquivo C em que estão definidas.

Exemplo de escopo de variável de vários arquivos

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

Compilação :

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

Saída :

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

Interpretação

  • existem duas variables ​​separadas para si , uma para cada arquivo
  • existe uma única variável compartilhada para i

Como de costume, quanto menor o escopo, melhor, então sempre declare as variables static se puder.

Na programação C, os arquivos são geralmente usados ​​para representar “classs” e static variables static representam membros estáticos privados da class.

O que os padrões dizem sobre isso

C99 N1256 versão 6.7.1 “Especificadores de class de armazenamento” diz que static é um “especificador de class de armazenamento”.

6.2.2 / 3 “Ligações de identificadores” diz que static implica internal linkage :

Se a declaração de um identificador de escopo de arquivo para um object ou uma function contiver o especificador de class de armazenamento estático, o identificador terá uma binding interna.

e 6.2.2 / 2 diz que internal linkage se comporta como no nosso exemplo:

No conjunto de unidades de tradução e bibliotecas que constituem um programa inteiro, cada declaração de um identificador particular com binding externa denota o mesmo object ou function. Dentro de uma unidade de tradução, cada declaração de um identificador com binding interna indica o mesmo object ou function.

onde “unidade de tradução é um arquivo de origem após o pré-processamento.

Como o GCC implementa para o ELF (Linux)?

Com a binding STB_LOCAL .

Se nós compilamos:

 int i = 0; static int si = 0; 

e desmonte a tabela de símbolos com:

 readelf -s main.o 

a saída contém:

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

então a binding é a única diferença significativa entre eles. Value é apenas o seu deslocamento para a seção .bss , então esperamos que seja diferente.

STB_LOCAL está documentado na especificação ELF em http://www.sco.com/developers/gabi/2003-12-17/ch4.symtab.html :

STB_LOCAL Os símbolos locais não são visíveis fora do arquivo de object que contém sua definição. Símbolos locais com o mesmo nome podem existir em vários arquivos sem interferir um com o outro

o que faz com que seja uma escolha perfeita para representar static .

Variáveis ​​sem estática são STB_GLOBAL e a especificação diz:

Quando o editor de links combina vários arquivos de objects relocáveis, ele não permite várias definições de símbolos STB_GLOBAL com o mesmo nome.

que é coerente com os erros de link em várias definições não estáticas.

Se aumentarmos a otimização com -O3 , o símbolo si é removido inteiramente da tabela de símbolos: ele não pode ser usado externamente. TODO por que manter variables ​​estáticas na tabela de símbolos quando não há otimização? Eles podem ser usados ​​para qualquer coisa? Talvez para debugging.

Veja também

Tente você mesmo

Exemplo no github para você brincar.

Depende:

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

A function retornaria 1, 2, 3, etc. — a variável não está na pilha.

ac:

 static int foo() { } 

Isso significa que essa function tem escopo apenas nesse arquivo. Então ac e bc podem ter foo() s diferentes, e foo não é exposto a objects compartilhados. Então, se você definiu foo em ac você não poderia acessá-lo de bc ou de qualquer outro lugar.

Na maioria das bibliotecas C, todas as funções “privadas” são estáticas e a maioria “pública” não é.

As pessoas continuam dizendo que ‘static’ em C tem dois significados. Eu ofereço uma maneira alternativa de visualizá-lo que lhe dá um significado único:

  • A aplicação de ‘static’ a um item força esse item a ter duas propriedades: (a) não é visível fora do escopo atual; (b) é persistente.

A razão pela qual parece ter dois significados é que, em C, cada item ao qual ‘estática’ pode ser aplicada já tem uma dessas duas propriedades , então parece que esse uso particular envolve apenas o outro.

Por exemplo, considere variables. As variables ​​declaradas fora das funções já têm persistência (no segmento de dados), portanto, aplicar ‘static’ só pode torná-las invisíveis fora do escopo atual (unidade de compilation). Pelo contrário, as variables ​​declaradas dentro de funções já não têm visibilidade fora do escopo atual (function), portanto, aplicar ‘static’ só pode torná-las persistentes.

A aplicação de ‘static’ a funções é como aplicá-lo a variables ​​globais – o código é necessariamente persistente (pelo menos dentro da linguagem), portanto, apenas a visibilidade pode ser alterada.

NOTA: Estes comentários aplicam-se apenas a C. Em C ++, a aplicação de ‘static’ a methods de class está realmente dando à palavra-chave um significado diferente. Da mesma forma, para a extensão do argumento de array C99.

static significa coisas diferentes em diferentes contextos.

  1. Você pode declarar uma variável estática em uma function C. Esta variável só é visível na function, no entanto, comporta-se como um global, uma vez que é inicializada apenas uma vez e retém o seu valor. Neste exemplo, toda vez que você chamar foo() ele imprimirá um número crescente. A variável estática é inicializada apenas uma vez.

     void foo () { static int i = 0; printf("%d", i); i++ } 
  2. Outro uso da estática é quando você implementa uma function ou variável global em um arquivo .c, mas não deseja que seu símbolo seja visível fora do .obj gerado pelo arquivo. por exemplo

     static void foo() { ... } 

Da Wikipedia:

Na linguagem de programação C, estática é usada com variables ​​globais e funções para definir seu escopo para o arquivo contido. Em variables ​​locais, estática é usada para armazenar a variável na memory alocada estaticamente em vez da memory alocada automaticamente. Enquanto a linguagem não determina a implementação de qualquer tipo de memory, a memory alocada estaticamente é normalmente reservada no segmento de dados do programa em tempo de compilation, enquanto a memory alocada automaticamente é normalmente implementada como uma pilha de chamadas temporária.

Eu odeio responder uma pergunta antiga, mas eu não acho que alguém tenha mencionado como K & R explicam isso na seção A4.1 de “The C Programming Language”.

Em suma, a palavra estática é usada com dois significados:

  1. Estático é uma das duas classs de armazenamento (a outra é automática). Um object estático mantém seu valor entre invocações. Os objects declarados fora de todos os blocos são sempre estáticos e não podem ser automáticos.
  2. Mas, quando a palavra-chave static (grande ênfase em ser usada no código como uma palavra-chave) é usada com uma declaração, ela dá àquele object a binding interna, de modo que ela só pode ser usada dentro daquela unidade de tradução. Mas se a palavra-chave é usada em uma function, ela muda a class de armazenamento do object (o object só seria visível dentro dessa function). O oposto de estática é a palavra-chave extern , que fornece um object de binding externa.

Peter Van Der Linden dá esses dois significados em “Expert C Programming”:

  • Dentro de uma function, mantém seu valor entre as chamadas.
  • No nível da function, visível apenas neste arquivo.

Se você declarar uma variável em uma function estática, seu valor não será armazenado na pilha de chamadas de function e ainda estará disponível quando você chamar a function novamente.

Se você declarar uma variável global estática, seu escopo será restrito ao arquivo no qual você a declarou. Isso é um pouco mais seguro do que um global regular, que pode ser lido e modificado em todo o seu programa.

Em C, estático tem dois significados, dependendo do escopo de seu uso. No escopo global, quando um object é declarado no nível do arquivo, isso significa que esse object é visível apenas nesse arquivo.

Em qualquer outro escopo, ele declara um object que reterá seu valor entre os diferentes horários em que o escopo específico é inserido. Por exemplo, se um int for delcarado dentro de um procedimento:

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

o valor de ‘i’ é inicializado como zero na primeira chamada do procedimento e o valor é retido a cada vez que o procedimento é chamado. se ‘i’ fosse impresso, produziria uma sequência de 0, 1, 2, 3, …

Se você declarar isso em um arquivo mytest.c:

 static int my_variable; 

Então esta variável só pode ser vista deste arquivo. A variável não pode ser exportada em nenhum outro lugar.

Se você declarar dentro de uma function, o valor da variável manterá seu valor toda vez que a function for chamada.

Uma function estática não pode ser exportada de fora do arquivo. Portanto, em um arquivo * .c, você está ocultando as funções e as variables, se as declarar estáticas.

É importante observar que variables ​​estáticas em funções são inicializadas na primeira input para essa function e persistem mesmo depois que sua chamada é finalizada; no caso de funções recursivas, a variável estática é inicializada apenas uma vez e persiste também sobre todas as chamadas recursivas e mesmo após a conclusão da chamada da function.

Se a variável foi criada fora de uma function, isso significa que o programador só é capaz de usar a variável no arquivo de origem que a variável foi declarada.

Também note que a static pode ser usada de 4 maneiras diferentes.

 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. 

Uma variável estática é uma variável especial que você pode usar em uma function e salva os dados entre as chamadas, e não os exclui entre as chamadas. Por exemplo:

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

A saída:

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

Variáveis ​​estáticas em C têm o tempo de vida do programa.

Se definidos em uma function, eles têm escopo local, isto é, eles podem ser acessados ​​apenas dentro dessas funções. O valor das variables ​​estáticas é preservado entre as chamadas de function.

Por exemplo:

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

No programa acima, var é armazenado no segmento de dados. Sua vida é o programa C inteiro.

Após a chamada de function 1, var se torna 2. Após a chamada de function 2, var se torna 3.

O valor de var não é destruído entre as chamadas de funções.

Se var tivesse entre variável não estática e local, ela seria armazenada no segmento de pilha no programa C. Como o quadro de pilha da function é destruído após a function retornar, o valor de var também é destruído.

As variables ​​estáticas inicializadas são armazenadas no segmento de dados do programa C, enquanto as não inicializadas são armazenadas no segmento BSS.

Outra informação sobre estática: Se uma variável é global e estática, ela tem o tempo de vida do programa em C, mas tem o escopo do arquivo. É visível apenas nesse arquivo.

Para tentar isso:

file1.c

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

arquivo2.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 

Agora tente ligá-los usando:

 gcc -o output file1.o file2.o 

Isso daria um erro de vinculador, já que x tem o escopo de arquivo de file1.c e o vinculador não seria capaz de resolver a referência à variável x usada em file2.c.

Referências:

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

Um valor de variável estática persiste entre diferentes chamadas de function e seu escopo é limitado ao bloco local que uma variável estática sempre inicializa com valor 0

Existem dois casos:

(1) Variáveis ​​locais declaradas static : Alocadas no segmento de dados em vez de pilha. Seu valor é retido quando você chama a function novamente.

(2) Variáveis ​​globais ou funções declaradas static : Unidade de compilation externa invisível (isto é, símbolos locais na tabela de símbolos durante a vinculação).