Eu já vi a palavra static
usada em diferentes lugares no código C; é como uma função / classe estática em C # (onde a implementação é compartilhada entre objetos)?
Eu já vi a palavra static
usada em diferentes lugares no código C; é como uma função / classe estática em C # (onde a implementação é compartilhada entre objetos)?
Respostas:
(1) é o tópico mais externo se você é um novato, então aqui está um exemplo:
#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();
}
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 nos casos em que uma função precisa manter algum estado entre as invocações e você não deseja usar variáveis globais. Cuidado, no entanto, esse recurso deve ser usado com moderação - torna seu código não seguro para threads e mais difícil de entender.
(2) É amplamente utilizado como um recurso de "controle de acesso". Se você tem um arquivo .c implementando alguma funcionalidade, normalmente expõe apenas algumas funções "públicas" para os usuários. O restante de suas funções deve ser feito static
, para que o usuário não possa acessá-las. Isso é encapsulamento, uma boa prática.
Citando a Wikipedia :
Na linguagem de programação C, estática é usada com variáveis e funções globais para definir seu escopo para o arquivo que contém. Nas variáveis locais, estático é usado para armazenar a variável na memória alocada estaticamente, em vez da memória alocada automaticamente. Enquanto o idioma não determina a implementação de qualquer tipo de memória, a memória alocada estaticamente é normalmente reservada no segmento de dados do programa em tempo de compilação, enquanto a memória alocada automaticamente é normalmente implementada como uma pilha de chamadas transitórias.
E para responder sua segunda pergunta, não é como em C #.
No C ++, no entanto, static
também é usado para definir atributos de classe (compartilhados entre todos os objetos da mesma classe) e métodos. Em C não há classes, portanto esse recurso é irrelevante.
.c
monte de arquivos de cabeçalho, mas o diabo está sempre no que não é típico.
Há mais um uso não abordado aqui, e isso é parte de uma declaração de tipo de matriz como argumento para uma função:
int someFunction(char arg[static 10])
{
...
}
Nesse contexto, isso especifica que os argumentos passados para essa função devem ser uma matriz do tipo char
com pelo menos 10 elementos. Para mais informações, veja minha pergunta aqui .
arg[0]
até arg[9]
a ter valores (o que também implica que a função não aceitar um ponteiro nulo). Os compiladores podem utilizar essas informações de alguma forma para otimização, e os analisadores estáticos podem utilizar essas informações para garantir que a função nunca receba um ponteiro nulo (ou, se puder dizer, uma matriz com menos elementos do que o especificado).
static
em C99. Tem mais de uma década e meia de idade, mas nem todos os escritores de compiladores adotaram todos os recursos do C99 - portanto, o C99 como um todo permanece amplamente desconhecido.
int arr[n];
, essa é uma VLA (matriz de comprimento variável) , que foi adicionada na C99. É isso que você quis dizer?
Resposta curta ... depende.
Variáveis locais definidas estáticas não perdem seu valor entre as chamadas de função. Em outras palavras, são variáveis globais, mas com escopo definido para a função local em que estão definidos.
Variáveis globais estáticas não são visíveis fora do arquivo C em que estão definidas.
Funções estáticas não são visíveis fora do arquivo C em que estão definidas.
private
em C, sua analogia é boa: estática torna as coisas "privadas" para um determinado arquivo. E os arquivos em C frequentemente são mapeados para classes em C ++.
Exemplo de escopo variável de vários arquivos
Aqui ilustro como a estática afeta o escopo das definições de função em vários arquivos.
ac
#include <stdio.h>
/*
Undefined behavior: already defined in main.
Binutils 2.24 gives an error and refuses to link.
/programming/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;
}
Compile e execute:
gcc -c a.c -o a.o
gcc -c main.c -o main.o
gcc -o main main.o a.o
Resultado:
m()
i = 1
si = 1
m()
i = 2
si = 2
a()
i = 3
si = 1
a()
i = 4
si = 2
Interpretação
si
, uma para cada arquivoi
Como de costume, quanto menor o escopo, melhor, sempre declare variáveis static
se puder.
Na programação C, os arquivos são frequentemente usados para representar "classes" e as static
variáveis representam membros estáticos privados da classe.
O que os padrões dizem sobre isso
C99 N1256 draft 6.7.1 "Especificadores da classe de armazenamento" diz que static
é um "especificador da classe de armazenamento".
6.2.2 / 3 "Ligações de identificadores" diz static
implica internal linkage
:
Se a declaração de um identificador de escopo de arquivo para um objeto ou uma função contiver o estático do especificador de classe de armazenamento, o identificador terá ligação 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 específico com ligação externa indica o mesmo objeto ou função. Dentro de uma unidade de conversão, cada declaração de um identificador com ligação interna indica o mesmo objeto ou função.
onde "a unidade de tradução é um arquivo de origem após o pré-processamento.
Como o GCC o implementa para o ELF (Linux)?
Com o STB_LOCAL
ligação.
Se compilarmos:
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
portanto, a ligação é a única diferença significativa entre eles. Value
é apenas o deslocamento para a .bss
seção, portanto 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 objeto que contém sua definição. Símbolos locais com o mesmo nome podem existir em vários arquivos sem interferir entre si
o que a torna 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 objetos realocá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 acionarmos a otimização -O3
, o si
símbolo será removido inteiramente da tabela de símbolos: ele não pode ser usado de fora de qualquer maneira. TODO por que manter variáveis estáticas na tabela de símbolos quando não há otimização? Eles podem ser usados para qualquer coisa? Talvez para depuração.
Veja também
static
funções: https://stackoverflow.com/a/30319812/895245static
com extern
, o que "faz o contrário": como uso extern para compartilhar variáveis entre arquivos de origem?Namespace anônimos em C ++
No C ++, convém usar espaços de nome anônimos em vez de estático, o que gera um efeito semelhante, mas oculta ainda mais as definições de tipo: espaços de nome anônimos / anônimos / funções estáticas
Depende:
int foo()
{
static int x;
return ++x;
}
A função retornaria 1, 2, 3 etc. - a variável não está na pilha.
static int foo()
{
}
Isso significa que esta função tem escopo apenas neste arquivo. Portanto, ac e bc podem ter foo()
s diferentes , e foo não é exposto a objetos compartilhados. Portanto, se você definiu foo em ac, não poderia acessá-lo de b.c
ou de outros lugares.
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 'estático' em C tem dois significados. Ofereço uma maneira alternativa de visualizá-lo, que lhe dá um único significado:
A razão pela qual parece ter dois significados é que, em C, todo item ao qual 'estático' pode ser aplicado já possui uma dessas duas propriedades , portanto parece que esse uso específico envolve apenas o outro.
Por exemplo, considere variáveis. As variáveis declaradas fora das funções já têm persistência (no segmento de dados), portanto, aplicar 'estático' só pode torná-las visíveis fora do escopo atual (unidade de compilação). Por outro lado, variáveis declaradas dentro de funções já não têm visibilidade fora do escopo atual (função), portanto, aplicar 'estático' só pode torná-las persistentes.
Aplicar 'estático' a funções é como aplicá-lo a variáveis globais - o código é necessariamente persistente (pelo menos no idioma), portanto, apenas a visibilidade pode ser alterada.
NOTA: Esses comentários se aplicam apenas a C. No C ++, aplicar 'estático' aos métodos de classe está realmente dando à palavra-chave um significado diferente. Da mesma forma para a extensão de argumento de matriz C99.
static
fornece ligação interna a um identificador.
Da Wikipedia:
Na linguagem de programação C, estática é usada com variáveis e funções globais para definir seu escopo para o arquivo que contém. Nas variáveis locais, estático é usado para armazenar a variável na memória alocada estaticamente, em vez da memória alocada automaticamente. Enquanto o idioma não determina a implementação de qualquer tipo de memória, a memória alocada estaticamente é normalmente reservada no segmento de dados do programa em tempo de compilação, enquanto a memória alocada automaticamente é normalmente implementada como uma pilha de chamadas transitórias.
static
significa coisas diferentes em diferentes contextos.
Você pode declarar uma variável estática em uma função C. Essa variável é visível apenas na função, no entanto, ela se comporta como um global, pois é inicializada apenas uma vez e mantém seu valor. Neste exemplo, toda vez que você ligar foo()
, imprimirá um número crescente. A variável estática é inicializada apenas uma vez.
void foo ()
{
static int i = 0;
printf("%d", i); i++
}
Outro uso de estático é quando você implementa uma função 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() { ... }
Se você declarar uma variável em uma função estática, seu valor não será armazenado na pilha de chamadas de funções e continuará disponível quando você chamar a função novamente.
Se você declarar uma variável global estática, seu escopo será restrito ao arquivo em que você a declarou. Isso é um pouco mais seguro que um global comum, que pode ser lido e modificado durante todo o programa.
Detesto responder a uma pergunta antiga, mas acho que ninguém mencionou como a K&R a explica na seção A4.1 de "A linguagem de programação C".
Em resumo, a palavra estática é usada com dois significados:
static
palavra - chave (grande ênfase em ser usada no código como palavra-chave) é usada com uma declaração, ela fornece a ligação interna ao objeto para que ela possa ser usada apenas dentro dessa unidade de tradução. Mas se a palavra-chave for usada em uma função, ela altera a classe de armazenamento do objeto (o objeto só seria visível dentro dessa função). O oposto de static é a extern
palavra - chave, que fornece a ligação externa a um objeto.Peter Van Der Linden dá esses dois significados em "Programação C Especialista":
register
um especificador de classe de armazenamento (C99 6.7.1 Especificadores de classe de armazenamento). E é mais do que apenas uma dica, por exemplo, você não pode aplicar o endereço do operador &
em um objeto com classe de armazenamento, register
independentemente de o compilador alocar um registro ou não.
Em C, estática tem dois significados, dependendo do escopo de seu uso. No escopo global, quando um objeto é declarado no nível do arquivo, significa que esse objeto é visível apenas dentro desse arquivo.
Em qualquer outro escopo, ele declara um objeto que manterá seu valor entre os diferentes momentos em que o escopo específico é inserido. Por exemplo, se um int for delcared dentro de um procedimento:
void procedure(void)
{
static int i = 0;
i++;
}
o valor de 'i' é inicializado como zero na primeira chamada para o procedimento e o valor é retido cada vez que o procedimento é chamado. se 'i' fosse impresso, produziria uma sequência de 0, 1, 2, 3, ...
É importante observar que variáveis estáticas nas funções são inicializadas na primeira entrada dessa função e persistem mesmo após o término da chamada; no caso de funções recursivas, a variável estática é inicializada apenas uma vez e persiste também em todas as chamadas recursivas e mesmo após o término da chamada da função.
Se a variável foi criada fora de uma função, significa que o programador só pode usar a variável no arquivo de origem em que a variável foi declarada.
Se você declarar isso em um mytest.c
arquivo:
static int my_variable;
Então essa variável pode ser vista apenas neste arquivo. A variável não pode ser exportada para nenhum outro lugar.
Se você declarar dentro de uma função, o valor da variável manterá seu valor sempre que a função for chamada.
Uma função estática não pode ser exportada de fora do arquivo. Portanto, em um *.c
arquivo, você está ocultando as funções e as variáveis se as declarar estáticas.
Variáveis estáticas em C têm a vida útil do programa.
Se definidos em uma função, eles têm escopo local, ou seja, podem ser acessados apenas dentro dessas funções. O valor das variáveis estáticas é preservado entre as chamadas de função.
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 útil é todo o programa C.
Após a chamada de função 1, var
torna-se 2. Após a chamada de função 2, var
torna-se 3.
O valor de var
não é destruído entre as chamadas de funções.
Se var
tivesse entre variáveis não estáticas e locais, seria armazenado no segmento de pilha no programa C. Como o quadro da pilha da função é destruído após o retorno da função, o valor de var
também é destruído.
Variáveis estáticas inicializadas são armazenadas no segmento de dados do programa C, enquanto variáveis não inicializadas são armazenadas no segmento BSS.
Outra informação sobre estática: se uma variável é global e estática, ela possui o tempo de vida do programa C, mas o escopo do arquivo. É visível apenas nesse arquivo.
Para tentar isso:
static int x;
int main()
{
printf("Accessing in same file%d", x):
}
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 vinculá-los usando:
gcc -o output file1.o file2.o
Isso causaria um erro de vinculador, pois x tem o escopo do arquivo file1.c e o vinculador não conseguiria resolver a referência à variável x usada no arquivo2.c.
Referências:
static int var = 1;
mudar o valor de volta para uma de cada vez
Uma variável estática é uma variável especial que você pode usar em uma função 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, ...
printf("%d, ", count); count++;
por `printf ("% d, ", count ++) (não que isso importe: P).
Existem 2 casos:
(1) Variáveis locais declaradas static
: alocadas no segmento de dados em vez da pilha. Seu valor é retido quando você chama a função novamente.
(2) Variáveis ou funções globais declaradas static
: Unidade de compilação externa invisível (ou seja, são símbolos locais na tabela de símbolos durante o vínculo).
As variáveis estáticas têm a propriedade de preservar seu valor mesmo depois de estarem fora do escopo! Portanto, as variáveis estáticas preservam o valor anterior no escopo anterior e não são inicializadas novamente no novo escopo.
Veja isso por exemplo - Uma variável int estática permanece na memória enquanto o programa está sendo executado. Uma variável normal ou automática é destruída quando uma chamada de função em que a variável foi declarada termina.
#include<stdio.h>
int fun()
{
static int count = 0;
count++;
return count;
}
int main()
{
printf("%d ", fun());
printf("%d ", fun());
return 0;
}
Isso produzirá: 1 2
Como 1 permanece na memória como foi declarado estático
Variáveis estáticas (como variáveis globais) são inicializadas como 0 se não forem inicializadas explicitamente. Por exemplo, no programa abaixo, o valor de x é impresso como 0, enquanto o valor de y é algo como lixo. Veja isso para mais detalhes.
#include <stdio.h>
int main()
{
static int x;
int y;
printf("%d \n %d", x, y);
}
Isso produzirá: 0 [some_garbage_value]
Estes são os principais que descobri que não foram explicados acima para um novato!
Na programação C, static
é uma palavra-chave reservada que controla a vida útil e a visibilidade. Se declararmos uma variável como estática dentro de uma função, ela será visível apenas em toda a função. Nesse uso, a vida útil dessa variável estática será iniciada quando uma chamada de função e será destruída após a execução dessa função. você pode ver o seguinte exemplo:
#include<stdio.h>
int counterFunction()
{
static int count = 0;
count++;
return count;
}
int main()
{
printf("First Counter Output = %d\n", counterFunction());
printf("Second Counter Output = %d ", counterFunction());
return 0;
}
O programa acima nos dará esta saída:
First Counter Output = 1
Second Counter Output = 1
Porque assim que chamarmos a função, ela inicializará o count = 0
. E enquanto executamos o, counterFunction
ele destruirá a variável count.