@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 ().
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(){staticint x =5;// assigns value of 5 only once
x++;
printf("%d", x);}int main(){
foo();// x = 6
foo();// x = 7return0;}
staticint x =5;void foo(){
x++;
printf("%d", x);}int main(){
foo();
foo();return0;}
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'.
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
staticint x =5;
não é o mesmo que
staticint 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.
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.
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(){staticint 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.
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.
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.
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.
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.
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 ){staticconstint 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.
Respostas:
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 ().
fonte
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,
fonte
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
fonte
Isso é o mesmo que ter o seguinte programa:
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
fonte
x
no principal; é global. No exemplo original,x
era local para foo, visível apenas enquanto dentro desse bloco, o que geralmente é preferível: se foo existe para manter dex
maneiras 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.c
, portanto, neste contexto, seu exemplo seria ilegal em âmbito global. (C requer inicializadores constantes para globais, C ++ não).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.
fonte
Produto: 6,7
Razão
A declaração de
x
está dentro,foo
mas ax=5
inicialização ocorre fora defoo
!O que precisamos entender aqui é que
não é o mesmo que
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çãofoo
até o fim da funçãofoo
. Por exemplo, eu verifiquei movendo a declaração para o final da função, e isso tornax
não declarado nax++;
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ávelx
nasce 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
x
usado quando coloquei uma funçãofoo
em 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 quex
tem o valor5
mesmo antes da primeira chamada parafoo
.fonte
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.fonte
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"
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
fonte
Vamos apenas ler o artigo da Wikipedia sobre variáveis estáticas ...
fonte
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.fonte
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.
fonte
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.
fonte
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:
é 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.
fonte