Em C, não notei nenhum efeito da extern
palavra - chave usada antes da declaração da função. No começo, pensei que, ao definir extern int f();
um único arquivo , você o implementa fora do escopo do arquivo. No entanto, descobri que ambos:
extern int f();
int f() {return 0;}
e
extern int f() {return 0;}
compile muito bem, sem avisos do gcc. Eu usei gcc -Wall -ansi
; nem aceitaria //
comentários.
Há algum efeito no uso extern
antes das definições de função ? Ou é apenas uma palavra-chave opcional, sem efeitos colaterais para funções.
No último caso, não entendo por que os designers padrão escolheram desarrumar a gramática com palavras-chave supérfluas.
EDIT: Para esclarecer, eu sei que não há uso para extern
em variáveis, mas eu só estou perguntando sobre extern
em funções .
Respostas:
Temos dois arquivos, foo.c e bar.c.
Aqui está foo.c
Agora, aqui está bar.c
Como você pode ver, não temos um cabeçalho compartilhado entre foo.c e bar.c, no entanto bar.c precisa de algo declarado em foo.c quando está vinculado, e foo.c precisa de uma função de bar.c quando está vinculado.
Ao usar 'extern', você está dizendo ao compilador que o que se segue será encontrado (não estático) no momento do link; não reserve nada para ele no passe atual, pois ele será encontrado posteriormente. Funções e variáveis são tratadas igualmente a esse respeito.
É muito útil se você precisar compartilhar algo global entre os módulos e não quiser colocá-lo / inicializá-lo em um cabeçalho.
Tecnicamente, todas as funções em um cabeçalho público da biblioteca são 'externas', no entanto, rotulá-las como tal tem muito pouco ou nenhum benefício, dependendo do compilador. A maioria dos compiladores pode descobrir isso por conta própria. Como você vê, essas funções são realmente definidas em outro lugar.
No exemplo acima, main () imprimiria olá mundo apenas uma vez, mas continuaria inserindo bar_function (). Observe também que bar_function () não retornará neste exemplo (já que é apenas um exemplo simples). Imagine o stop_now sendo modificado quando um sinal for atendido (portanto, volátil) se isso não parecer prático o suficiente.
Os externos são muito úteis para coisas como manipuladores de sinal, um mutex que você não deseja colocar em um cabeçalho ou estrutura, etc. A maioria dos compiladores será otimizada para garantir que eles não reservem memória para objetos externos, pois sabem que eles o reservará no módulo em que o objeto está definido. No entanto, novamente, há pouco sentido em especificá-lo com compiladores modernos ao prototipar funções públicas.
Espero que ajude :)
fonte
bar.c
e a declaração emfoo.c
. Se a função for declaradafoo.h
e os dois arquivos incluíremfoo.h
, o cabeçalho aplicará consistência entre os dois arquivos de origem. Sem ele, se a definição debar_function
in forbar.c
alterada, mas a declaração infoo.c
não for alterada, as coisas darão errado no tempo de execução; o compilador não consegue identificar o problema. Com um cabeçalho usado corretamente, o compilador identifica o problema.Tanto quanto me lembro do padrão, todas as declarações de função são consideradas "externas" por padrão, portanto não há necessidade de especificá-lo explicitamente.
Isso não torna essa palavra-chave inútil, pois também pode ser usada com variáveis (e nesse caso - é a única solução para resolver problemas de ligação). Mas com as funções - sim, é opcional.
fonte
Você precisa distinguir entre dois conceitos separados: definição de função e declaração de símbolo. "extern" é um modificador de ligação, uma dica para o compilador sobre onde o símbolo referido posteriormente é definido (a dica é "não aqui").
Se eu escrever
no escopo do arquivo (fora de um bloco de função) em um arquivo C, você está dizendo "a variável pode ser definida em outro lugar".
é uma declaração da função f e uma definição da função f. A definição neste caso substitui o externo.
é primeiro uma declaração, seguida pela definição.
O uso de
extern
está errado se você deseja declarar e definir simultaneamente uma variável de escopo do arquivo. Por exemplo,dará um erro ou aviso, dependendo do compilador.
O uso de
extern
é útil se você desejar explicitamente evitar a definição de uma variável.Deixe-me explicar:
Digamos que o arquivo ac contenha:
O arquivo ah inclui:
e o arquivo bc contém:
O externo no cabeçalho é útil, porque informa ao compilador durante a fase do link "esta é uma declaração e não uma definição". Se eu remover a linha em ac que define i, alocar espaço para ela e atribuir um valor a ela, o programa falhará ao compilar com uma referência indefinida. Isso informa ao desenvolvedor que ele se referiu a uma variável, mas ainda não a definiu. Se, por outro lado, eu omito a palavra-chave "extern" e removo a
int i = 2
linha, o programa ainda compila - eu será definido com o valor padrão 0.As variáveis de escopo do arquivo são definidas implicitamente com um valor padrão de 0 ou NULL se você não atribuir explicitamente um valor a elas - diferentemente das variáveis de escopo de bloco que você declara na parte superior de uma função. A palavra-chave extern evita essa definição implícita e, assim, ajuda a evitar erros.
Para funções, nas declarações de função, a palavra-chave é realmente redundante. As declarações de função não têm uma definição implícita.
fonte
int i = 2
linha no terceiro parágrafo? E é correto afirmar, vendoint i;
, o compilador alocará memória para essa variável, mas vendoextern int i;
, o compilador NÃO alocará memória, mas procurará a variável em outro lugar?A
extern
palavra-chave assume diferentes formas, dependendo do ambiente. Se uma declaração estiver disponível, aextern
palavra-chave utilizará a ligação conforme especificado anteriormente na unidade de tradução. Na ausência de qualquer declaração,extern
especifica a ligação externa.Aqui estão os parágrafos relevantes do projeto C99 (n1256):
fonte
As funções embutidas têm regras especiais sobre o que
extern
significa. (Observe que as funções embutidas são uma extensão C99 ou GNU; elas não estavam no C. originalPara funções não embutidas,
extern
não é necessário, pois está ativado por padrão.Observe que as regras para C ++ são diferentes. Por exemplo,
extern "C"
é necessário na declaração C ++ das funções C que você chamará do C ++, e existem regras diferentesinline
.fonte
Por isso, 10 anos depois:
extern
na declaração de função para remoção;git/git
segue essa conclusão e removeextern
do seu código (para Git 2.22, Q2 2019).Veja commit ad6dad0 , commit b199d71 , commit 5545442 (29 Abr 2019) por Denton Liu (
Denton-L
) .(Incorporado por Junio C Hamano -
gitster
- in commit 4aeeef3 , 13 de maio de 2019)Isso nem sempre é simples:
Veja commit 7027f50 (04 set 2019) por Denton Liu (
Denton-L
) .(Mesclado por Denton Liu -
Denton-L
- in commit 7027f50 , 05 set 2019)Observe que, com o Git 2.24 (quarto trimestre de 2019), qualquer espúria
extern
é descartada.Veja commit 65904b8 (30 set 2019) por Emily Shaffer (
nasamuffin
) .Ajudado por: Jeff King (
peff
) .Veja commit 8464f94 (21 de setembro de 2019) de Denton Liu (
Denton-L
) .Ajudado por: Jeff King (
peff
) .(Incorporado por Junio C Hamano -
gitster
- in commit 59b19bc , 07 out 2019)fonte
A
extern
palavra-chave informa ao compilador que a função ou variável possui ligação externa - em outras palavras, que é visível em arquivos diferentes daquele em que está definida. Nesse sentido, tem o significado oposto àstatic
palavra - chave. É um pouco estranho colocarextern
no momento da definição, pois nenhum outro arquivo teria visibilidade da definição (ou isso resultaria em várias definições). Normalmente, você colocaextern
uma declaração em algum momento com visibilidade externa (como um arquivo de cabeçalho) e coloca a definição em outro lugar.fonte
declarar uma função extern significa que sua definição será resolvida no momento da vinculação, não durante a compilação.
Diferentemente das funções regulares, que não são declaradas externas, ele pode ser definido em qualquer um dos arquivos de origem (mas não em vários arquivos de origem), caso contrário, você receberá um erro de vinculador dizendo que forneceu várias definições da função) incluindo a declarado extern.So, no caso de o vinculador resolver a definição da função no mesmo arquivo.
Eu não acho que fazer isso seria muito útil, mas fazer esse tipo de experimento fornece uma melhor visão sobre como o compilador e o vinculador da linguagem funcionam.
fonte
A razão pela qual não tem efeito é que, no momento do link, o vinculador tenta resolver a definição externa (no seu caso
extern int f()
). Não importa se o encontra no mesmo arquivo ou em um arquivo diferente, desde que seja encontrado.espero que isso responda sua pergunta.
fonte
extern
a qualquer função?