Ir ao conteúdo
  • Cadastre-se

C Especificadores extern e static


Ir à solução Resolvido por arfneto,

Posts recomendados

Boa noite, colegas.

Estava dando uma olhada no livro C: Como Programar 6ª edição, e me deparei com o seguinte:

Citação

Variáveis globais e nomes de funções são da classe de armazenamento extern, como padrão.

E mais adiante, o autor diz:

Citação

variáveis declaradas fora das definições de função são da classe de memória static, por default, e são conhecidas como variáveis globais.

E bem, vejo que ele disse o mesmo sobre os dois especificadores de classe de armazenamento... 🤔

O único uso que conheço do extern é para referenciar variáveis globais e funções em outro arquivo, daí declaramos a variável ou função precedida por extern, mas não acho que variáveis globais e funções sejam precedidas por extern por padrão... Não seriam precedidas por static? Qual seria o certo?

  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

13 horas atrás, Lucca Rodrigues disse:

não acho que variáveis globais e funções sejam precedidas por extern por padrão... Não seriam precedidas por static? Qual seria o certo?

 

O livro.

 

Se coloque no lugar do linker...

 

pense nesses arquivos:

 

umx.c
 

// umx.c
    int x = 42;

outrox.c

 

// outrox.c
    int x = 4242;

 

E compile os dois:
 

    gcc -c umx.c outrox.c

 

Sem problemas. Nos dois casos x é extern porque afinal não está dentro de nada para ser interno. E deve ser static porque tem que ser criado e não está dentro de nenhum contexto.

 

Agora pense (no lugar do linker) nesse programa, maisum.c 
 

// maisum.c
#include <stdio.h>

int (existe)(int);

void quanto(int x)
{
    // chama alguma f() que veio
    printf( "quanto(%d): x = %d\n", x,  existe(x) );
}

 

Esse programa  cria a função quanto() que mostra o valor de x, só que x é um parâmetro, nem static nem extern.

Só que declara existe() que obviamente é extern porque aqui não está.

 

Agora em main.c a conta precisa fechar:
 

#include <stdio.h>

extern int x;
void quanto(int);

int existe(int x){ printf("existe(%d)\n", x); return x; };

int main(void)
{
    printf("main() x= %d\n", x );
    quanto(x);
    return 0;   
}

 

a função existe() que faltava é criada aqui. E tem seu próprio x. Mas main() vai usar o  x global e chamar quanto() com o valor desse x.

 

Claro, x não precisa ser extern mas se quiser x por exemplo como uma semente para rand() que vem de algum lugar central, vai deixar como extern e contar que isso se resolva na hora do build. 

 

Claro, quanto() poderia ser declarada extern mas é implícito porque afinal aqui ela não está.

 

E claro que não pode incluir umx.c ou outrox.c no build (link) porque vai duplicar ou triplicar x.

 

E se rodar
 

gcc -c -Wall umx.c
gcc -c -Wall outrox.c
gcc -c -Wall maisum.c

echo "// um usa umx.c "
./um
gcc -o um main.c maisum.o umx.o -l c

echo "// dois usa outrox.c "
./dois
gcc -o outro main.c maisum.o outrox.o -l c

 

vai ver 
 

// um usa umx.c 
main() x= 42
existe(42)
quanto(42): x = 42
// dois usa outrox.c 
main() x= 4242
existe(4242)
quanto(4242): x = 4242

 

 

E faz sentido.

 

Tente

    gcc -o juntos main.c maisum.o umx.o outrox.o -l c

 

E vai ver

 

/usr/bin/ld: outrox.o:(.data+0x0): 
    multiple definition of `x'; umx.o:(.data+0x0): first defined here
collect2: error: ld returned 1 exit status

 

 

 

  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

@arfneto

2 horas atrás, arfneto disse:

Esse programa  cria a função quanto() que mostra o valor de x, só que x é um parâmetro, nem static nem extern.

De certo modo, `x` seria auto :D

É uma variável local de quanto().

 

2 horas atrás, arfneto disse:

Nos dois casos x é extern porque afinal não está dentro de nada para ser interno. E deve ser static porque tem que ser criado e não está dentro de nenhum contexto.

Não entendi muito bem essa segunda afirmação... extern e static não são mutualmente exclusivos?

Havia dito que:

16 horas atrás, Lucca Rodrigues disse:

não acho que variáveis globais e funções sejam precedidas por extern por padrão... Não seriam precedidas por static?

porque usar extern seria dizer que a variável estaria definida em outro lugar, e que essa declaração nada mais é que uma referenciação à definição, mas acho que isso seria só quando usamos extern explicitamente, a menos que estejamos tratando de protótipos de função, como você disse:

2 horas atrás, arfneto disse:

Claro, quanto() poderia ser declarada extern mas é implícito porque afinal aqui ela não está.

extern não faria diferença nesse caso.

Mas novamente, extern e static não são mutualmente exclusivos? Uma variável com static só pode ser acessada pelas funções do mesmo arquivo em que foi definida, e o mesmo vale para as funções definidas com static, certo?

Me surgiram outras dúvidas (duvidosas)...

E se definirmos uma função com extern? Não que faça sentido 🤪, até porque acho que a definição não deixaria de ser uma definição só porque está precedida por extern.

E se declararmos um protótipo de função precedido por static num arquivo diferente de onde está a definição? Faria alguma diferença?

Link para o comentário
Compartilhar em outros sites

  • Solução
1 hora atrás, Lucca Rodrigues disse:

De certo modo, `x` seria auto :D

É uma variável local de quanto().

 

 

auto significa praticamente nada em C. Ou nada mesmo. Sugiro esquecer. 

 

Em C++ é outra coisa, especialmente com templates e coisas tipo &&
 

3 horas atrás, arfneto disse:

Nos dois casos x é extern porque afinal não está dentro de nada para ser interno. E deve ser static porque tem que ser criado e não está dentro de nenhum contexto

 

1 hora atrás, Lucca Rodrigues disse:

Não entendi muito bem essa segunda afirmação... extern e static não são mutualmente exclusivos?

 

 

Não. E não poderiam ser. Veja o exemplo.

 

Pense como o linker. Ele precisa fazer algo com o programa. Contexto aqui é scope. Em

 

// programa 

int x;
int y = x;
// fim

 

que vai fazer com x e y? claro que tem que ser alocados. E o scope tem que ser global. Se não fosse estaria onde? A menos que isso fosse incluído em um programa... ;) E assim são static, porque vão ter escopo global.

 

1 hora atrás, Lucca Rodrigues disse:

extern não faria diferença nesse caso

 

todo protótipo declara a função como extern. Se ela aparecer depois no mesmo arquivo aí passa a ser local... Mas ao ler o protótipo o compilador não sabe. É pra isso que existe o protótipo afinal.

 

1 hora atrás, Lucca Rodrigues disse:

Uma variável com static só pode ser acessada pelas funções do mesmo arquivo em que foi definida, e o mesmo vale para as funções definidas com static, certo?

 

Isso não é o mais importante: o importante é que variáveis estáticas são alocadas uma única vez (linker) e não a cada chamada da função. É o mesmo caso com main() que é uma função, só que em geral main() não é chamada de novo...

Isso implica em que o endereço de uma variável estática dentro da função é constante, ao contrário das outras variáveis, que são recriadas a cada chamada.

 

funções static acabam assim existindo no contexto do arquivo  porque o linker coloca o código da função em um segmento separado para esse particular bloco de código, então endereço será desconhecido fora dele.

 

1 hora atrás, Lucca Rodrigues disse:

E se definirmos uma função com extern? Não que faça sentido

 

4 horas atrás, arfneto disse:

Claro, quanto() poderia ser declarada extern mas é implícito porque afinal aqui ela não está.

 

pois é. auto para as variáveis não quer dizer nada, extern para as funções não quer dizer nada. A menos que tenha um código enorme com múltiplos #include por exemplo e queira ter certeza de que ninguém dentro dele define uma certa função cujo protótipo está no header

 

1 hora atrás, Lucca Rodrigues disse:

E se declararmos um protótipo de função precedido por static num arquivo diferente de onde está a definição? Faria alguma diferença?

 

 

Deve gerar um warning ao menos. Mas desde que o linker encontre uma no caminho vai gerar o código.

 

 

 

 

  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...

Curso de Redes MikroTik

LANÇAMENTO!

CLIQUE AQUI PARA SE INSCREVER!

* Este curso não é ministrado pela equipe do Clube do Hardware.