Variável estática dentro de uma função em C


119

O que será impresso? 6 6 ou 6 7? E porque?

void foo()
{
    static int x = 5;
    x++;
    printf("%d", x);
}

int main()
{
    foo();
    foo();
    return 0;
}

54
Qual é o problema para tentar?
— Andrew

12
Você tentou digitar isso e ver por si mesmo?
— wilhelmtell

20
Eu quero entender o porquê.
— Vadiklk

7
@Vadiklk então faça perguntas começando com "Por quê"
— Andrey

1
ideone.com/t9Bbe O que você esperava? O resultado não corresponde à sua expectativa? Por que você esperava seu resultado?
— eckes

Respostas:


186

Existem duas questões aqui, vida útil e escopo.

O escopo da variável é onde o nome da variável pode ser visto. Aqui, x é visível apenas dentro da função foo ().

O tempo de vida de uma variável é o período durante o qual ela existe. Se x fosse definido sem a palavra-chave static, o tempo de vida seria da entrada em foo () até o retorno de foo (); então ele seria reinicializado para 5 em cada chamada.

A palavra-chave static atua para estender o tempo de vida de uma variável para o tempo de vida do programa; por exemplo, a inicialização ocorre apenas uma vez e então a variável retém seu valor - seja lá o que for - em todas as chamadas futuras para foo ().


15
@devanl, sim, nós somos.
— orion elenzil

1
Simples e lógico :)
— Dimitar Vukman

em quais cenários precisamos declarar uma variável como estática dentro de uma função ?, apenas curioso para saber como eu não usei isso antes?
— Akay

Eu diria obrigado, mas tudo isso foi respondido no topo da página. me faz rir que as pessoas não executam apenas seus próprios códigos. xD
— Puddle

Essa resposta está errada. No momento em que você pensa sobre funções recursivas, as definições descritas aqui não explicam o comportamento!
— Philip Couling

52

Produto : 6 7

Motivo : a variável estática é inicializada apenas uma vez (ao contrário da variável automática) e a definição posterior da variável estática seria ignorada durante o tempo de execução. E se não for inicializado manualmente, é inicializado pelo valor 0 automaticamente. Assim,

void foo() {
    static int x = 5; // assigns value of 5 only once
    x++;
    printf("%d", x);
}

int main() {
    foo(); // x = 6
    foo(); // x = 7
    return 0;
}

10

6 7

o compilador faz com que a inicialização da variável estática não aconteça cada vez que a função é inserida


10

Isso é o mesmo que ter o seguinte programa:

static int x = 5;

void foo()
{
    x++;
    printf("%d", x);
}

int main()
{
     foo();
     foo();
     return 0;
}

Tudo o que a palavra-chave estática faz nesse programa é dizer ao compilador (essencialmente) 'ei, eu tenho uma variável aqui que não quero que ninguém mais acesse, não diga a ninguém que ela existe'.

Dentro de um método, a palavra-chave estática diz ao compilador o mesmo que acima, mas também, 'não diga a ninguém que isso existe fora desta função, só deve estar acessível dentro desta função'.

Eu espero que isso ajude


13
Bem, na verdade não é o mesmo. Ainda há o problema de escopo em X. Neste exemplo, você poderia cutucar e atacar com xno principal; é global. No exemplo original, xera local para foo, visível apenas enquanto dentro desse bloco, o que geralmente é preferível: se foo existe para manter de xmaneiras previsíveis e visíveis, então deixar que outros cutuquem é geralmente perigoso. Como outro benefício de mantê-lo dentro do escopo, foo() ele também é foo()portátil.
— user2149140

2
@ user2149140 'não diga a ninguém que isso existe fora desta função, só deve estar acessível dentro desta função'
— DCShannon 01 de

3
Embora você tenha abordado a questão do escopo devido a onde a variável é declarada, a descrição de estática como afetando o escopo, em vez do tempo de vida, parece incorreta.
— DCShannon 01 de

1
@Chameleon A questão está marcada como c, portanto, neste contexto, seu exemplo seria ilegal em âmbito global. (C requer inicializadores constantes para globais, C ++ não).
— Richard J. Ross III

5

Uma variável estática dentro de uma função tem uma vida útil enquanto seu programa é executado. Ele não será alocado sempre que sua função for chamada e desalocada quando sua função retornar.


Dizer que isso é como uma variável "global" e, em seguida, dizer EXCETO que você não pode acessá-la é um oxímoro. Global significa acessível em qualquer lugar. Que neste caso de uma função estática DENTRO de uma função NÃO está acessível em todos os lugares. A questão no OP, como outros observaram, é sobre escopo e tempo de vida. Por favor, não confunda as pessoas com o uso do termo 'global' e enganando-as sobre o escopo da variável.
— ChuckB

@ChuckB: Correto. Corrigido. Bem, já se passaram 6 anos. Minha resposta anterior teve a percepção de 6 anos atrás!
— Donotalo,

5

Produto: 6,7

Razão

A declaração de xestá dentro, foomas a x=5inicialização ocorre fora de foo!

O que precisamos entender aqui é que

static int x = 5;

não é o mesmo que

static int x;
x = 5;

Outras respostas usaram as palavras importantes aqui, escopo e tempo de vida, e apontaram que o escopo de xé do ponto de sua declaração na função fooaté o fim da função foo. Por exemplo, eu verifiquei movendo a declaração para o final da função, e isso torna xnão declarado na x++;declaração.

Portanto, a parte static int x(escopo) da instrução realmente se aplica onde você a lê, em algum lugar DENTRO da função e apenas a partir daí, não acima dela dentro da função.

No entanto, a parte x = 5(vitalícia) da instrução é a inicialização da variável e ocorrendo FORA da função como parte do carregamento do programa. A variável xnasce com um valor de5 quando o programa é carregado.

Eu li isso em um dos comentários: " Além disso, isso não resolve a parte realmente confusa, que é o fato de que o inicializador é ignorado nas chamadas subsequentes. " Ele é ignorado em todas as chamadas. A inicialização da variável está fora do código de função adequado.

O valor de 5 é teoricamente definido independentemente de foo ser ou não chamado, embora um compilador possa otimizar a função se você não a chamar em qualquer lugar. O valor 5 deve estar na variável antes de foo ser chamado.

Dentro de foo, a declaraçãostatic int x = 5; é improvável que gere qualquer código.

Eu descobri o endereço xusado quando coloquei uma função fooem um programa meu e então (corretamente) adivinhei que o mesmo local seria usado se eu executasse o programa novamente. A captura de tela parcial abaixo mostra que xtem o valor 5mesmo antes da primeira chamada para foo.

Break Point antes da primeira chamada para foo


2

A saída será 6 7 . Uma variável estática (dentro de uma função ou não) é inicializada exatamente uma vez, antes de qualquer função nessa unidade de tradução ser executada. Depois disso, ele mantém seu valor até ser modificado.


1
Tem certeza de que a estática é inicializada antes de a função ser chamada, e não na primeira chamada da função?
— Jesse Pepper

@JessePepper: Pelo menos se falta memória, isso depende se você está falando sobre C ++ 98/03 ou C ++ 11. Em C ++ 98/03, acredito que seja conforme descrito acima. No C ++ 11, o threading torna isso essencialmente impossível de fazer, então a inicialização é feita na primeira entrada na função.
— Jerry Coffin

2
Acho que você está errado, na verdade. Acho que mesmo antes do C ++ 11 ele só foi inicializado quando a função é chamada. Isso é importante para uma solução comum para o problema de dependência de inicialização estática.
— Jesse Pepper

2

Vadiklk,

Por quê ...? A razão é que a variável estática é inicializada apenas uma vez e mantém seu valor em todo o programa. significa que você pode usar a variável estática entre as chamadas de função. também pode ser usado para contar "quantas vezes uma função é chamada"

main()
{
   static int var = 5;
   printf("%d ",var--);
   if(var)
      main();
} 

e a resposta é 5 4 3 2 1 e não 5 5 5 5 5 5 .... (loop infinito) como você está esperando. novamente, o motivo pelo qual a variável estática é inicializada uma vez, na próxima vez que main () for chamado, ela não será inicializada em 5 porque já foi inicializada no programa. Portanto, podemos alterar o valor, mas não podemos reinicializar. É assim que funciona a variável estática.

ou você pode considerar como por armazenamento: variáveis ​​estáticas são armazenadas na seção de dados de um programa e variáveis ​​que são armazenadas na seção de dados são inicializadas uma vez. e antes da inicialização, eles são mantidos na seção BSS.

Por sua vez, as variáveis ​​Auto (locais) são armazenadas na pilha e todas as variáveis ​​na pilha são reinicializadas o tempo todo quando a função é chamada, pois um novo FAR (registro de ativação da função) é criado para isso.

ok para mais compreensão, faça o exemplo acima sem "estático" e deixe você saber qual será o resultado. Isso faz você entender a diferença entre os dois.

Obrigado Javed


1

Vamos apenas ler o artigo da Wikipedia sobre variáveis ​​estáticas ...

Variáveis ​​locais estáticas: as variáveis ​​declaradas como estáticas dentro de uma função são alocadas estaticamente, embora tenham o mesmo escopo das variáveis ​​locais automáticas. Portanto, quaisquer valores que a função coloque em suas variáveis ​​locais estáticas durante uma chamada ainda estarão presentes quando a função for chamada novamente.


5
Isso é terrível! "variáveis ​​declaradas como estáticas dentro de uma função são alocadas estaticamente" - isso não explica nada, a menos que você já saiba o que significa!

@Blank: bem, pensei que era para isso que servia a segunda frase. Embora eu ache que você está certo, deveria ser mais bem formulado.
— Andrew White

Além disso, isso não resolve a parte realmente confusa, que é o fato de que o inicializador é ignorado nas chamadas subsequentes.
— Tom Auger

alocado estaticamente significa nenhuma pilha, nem heap.
— Camaleão de

1

Você obterá 6 7 impresso como, como é facilmente testado, e aqui está o motivo: Quando fooé chamada pela primeira vez, a variável estática x é inicializada para 5. Em seguida, é incrementada para 6 e impressa.

Agora para a próxima chamada para foo. O programa pula a inicialização da variável estática e, em vez disso, usa o valor 6 que foi atribuído ax da última vez. A execução prossegue normalmente, fornecendo o valor 7.


1
6 7

x é uma variável global visível apenas a partir de foo (). 5 é seu valor inicial, conforme armazenado na seção .data do código. Qualquer modificação subsequente sobrescreverá o valor anterior. Não há código de atribuição gerado no corpo da função.


1

6 e 7 Como a variável estática inicializa apenas uma vez, So 5 ++ torna-se 6 na 1ª chamada 6 ++ torna-se 7 na 2ª chamada Nota - quando ocorre a 2ª chamada, o valor de x é 6 em vez de 5 porque x é a variável estática.


0

No C ++ 11, pelo menos, quando a expressão usada para inicializar uma variável estática local não é um 'constexpr' (não pode ser avaliada pelo compilador), então a inicialização deve acontecer durante a primeira chamada para a função. O exemplo mais simples é usar diretamente um parâmetro para inicializar a variável estática local. Portanto, o compilador deve emitir código para adivinhar se a chamada é a primeira ou não, o que, por sua vez, requer uma variável booleana local. Compilei esse exemplo e verifiquei se isso é verdade, vendo o código do assembly. O exemplo pode ser assim:

void f( int p )
{
  static const int first_p = p ;
  cout << "first p == " << p << endl ;
}

void main()
{
   f(1); f(2); f(3);
}

é claro, quando a expressão é 'constexpr', então isso não é necessário e a variável pode ser inicializada no carregamento do programa usando um valor armazenado pelo compilador no código assembly de saída.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.