Quando usar extern em C ++

399

Estou lendo "Think in C ++" e ele acabou de apresentar a externdeclaração. Por exemplo:

extern int x;
extern float y;

Acho que entendi o significado (declaração sem definição), mas me pergunto quando isso se mostra útil.

Alguém pode dar um exemplo?

Aslan986
fonte
11
Eu tive que fornecer uma definição externem várias ocasiões. As ferramentas da Microsoft produziram um erro de link para os símbolos ausentes quando as tabelas em outro arquivo de origem foram definidas apenas. O problema era que a tabela estava conste o compilador C ++ a promoveu staticna unidade de tradução. Veja, por exemplo, ariatab.cppe kalynatab.cpp.
JWW
2
E acho que a resposta de Nik é a correta, porque ele é o único que parece ter respondido a uma pergunta em C ++. Todos os outros parecem ter se desviado para uma pergunta em C.
JWW

Respostas:

520

Isso é útil quando você tem variáveis ​​globais. Você declara a existência de variáveis ​​globais em um cabeçalho, para que cada arquivo de origem que inclua o cabeçalho saiba sobre ele, mas você só precisa “defini-lo” uma vez em um dos seus arquivos de origem.

Para esclarecer, usar extern int x;informa ao compilador que um objeto do tipo intchamado xexiste em algum lugar . Não é tarefa dos compiladores saber onde ele existe, ele só precisa saber o tipo e o nome para saber como usá-lo. Depois que todos os arquivos de origem forem compilados, o vinculador resolverá todas as referências xà definição encontrada em um dos arquivos de origem compilados. Para que funcione, a definição da xvariável precisa ter o que é chamado de "ligação externa", o que basicamente significa que precisa ser declarada fora de uma função (no que geralmente é chamado de "escopo do arquivo") e sem a staticpalavra - chave.

cabeçalho:

#ifndef HEADER_H
#define HEADER_H

// any source file that includes this will be able to use "global_x"
extern int global_x;

void print_global_x();

#endif

fonte 1:

#include "header.h"

// since global_x still needs to be defined somewhere,
// we define it (for example) in this source file
int global_x;

int main()
{
    //set global_x here:
    global_x = 5;

    print_global_x();
}

fonte 2:

#include <iostream>
#include "header.h"

void print_global_x()
{
    //print global_x here:
    std::cout << global_x << std::endl;
}
dreamlax
fonte
15
Obrigado. Então, se eu declarar uma variável global em um arquivo de cabeçalho sem a palavra-chave externa, os arquivos de origem que incluem o cabeçalho não a veem?
Aslan986
23
você não deve declarar vars globais em um cabeçalho, porque, então, quando 2 arquivos incluem o mesmo arquivo de cabeçalho, não vai link (vinculador emitirá um erro sobre "símbolo duplicado")
kuba
63
@ Aslan986: Não, algo pior acontece. Cada arquivo de origem que inclui o cabeçalho terá sua própria variável; portanto, cada arquivo de origem será compilado independentemente, mas o vinculador reclamará porque dois arquivos de origem terão os mesmos identificadores globais.
dreamlax
7
Quando você não usa a palavra "extern", agora a variável existe. Quando você usa "extern", é um "ei, existe esse var em outro lugar". Desculpe por não responder se é uma definição ou declaração, já que sempre fico confuso com esses dois.
Kay
3
@CCJ: o protetor de inclusão funciona apenas para o arquivo de origem que o está incluindo. Ele impede que o mesmo cabeçalho seja incluído duas vezes no mesmo arquivo de origem (caso outros cabeçalhos também o incluam, etc.). Portanto, mesmo com a inclusão de guardas, cada arquivo de origem que inclui o cabeçalho ainda terá sua própria definição.
dreamlax
172

É útil quando você compartilha uma variável entre alguns módulos. Você o define em um módulo e usa extern nos outros.

Por exemplo:

em file1.cpp:

int global_int = 1;

em file2.cpp:

extern int global_int;
//in some function
cout << "global_int = " << global_int;
MByD
fonte
39
Essa resposta é mais correta do que a aceita, pois não utiliza o arquivo de cabeçalho e afirma claramente que é útil apenas ao compartilhar entre poucos módulos. Para aplicativos maiores, é melhor usar, por exemplo, uma classe ConfigManager.
Zac
11
Existe alguma dica quando os espaços para nome estão envolvidos, global_intestá no espaço para nome global, se eu fosse usá-lo em file2.cpp em alguma seção do espaço para nome, teria que definir o escopo corretamente? isto é,namespace XYZ{ void foo(){ ::global_int++ } };
jxramos
8
@ Zac: Por outro lado, ao não declarar uma variável global em um cabeçalho, você inadvertidamente tornou muito mais difícil determinar onde ela está realmente definida. Geralmente, se você vê uma variável global declarada em abc.h, há uma boa chance de ser definida em abc.cpp. Um bom IDE sempre ajudará, mas um código bem organizado é sempre uma solução melhor.
dreamlax
sem externem file2.cpp, ainda é possível acessar o global_intafter include. Por que eu preciso disso?
TomSawyer 26/04
62

É tudo sobre a ligação .

As respostas anteriores forneceram boas explicações sobre extern.

Mas quero acrescentar um ponto importante.

Você pergunta externem C ++ e não em C e não sei por que não há resposta mencionando o caso quando externvem com constC ++.

Em C ++, uma constvariável possui ligação interna por padrão (não como C).

Portanto, este cenário levará ao erro de vinculação :

Fonte 1:

const int global = 255; //wrong way to make a definition of global const variable in C++

Fonte 2:

extern const int global; //declaration

Precisa ser assim:

Fonte 1:

extern const int global = 255; //a definition of global const variable in C++

Fonte 2:

extern const int global; //declaration
Trevor
fonte
2
Por que está errado enquanto trabalha em c ++ sem incluir 'extern' na parte de definição?
Chief Shifter
11
Parece que não encontro esse erro de vinculação no Visual Studio com o Visual Micro. o que estou perdendo?
precisa saber é o seguinte
11
@ lartist93 @ Craig.Feied Eu acredito que você pode precisar verificar novamente com cuidado. Mesmo que o compilador não informe o erro de vinculação, você poderia verificar se os dois objetos na origem são iguais sem externdefinição? Você poderia fazer isso imprimindo o valor da globalfonte 2. #
Trevor
3
Confirmar, em MSVS 2018 Não é um erro que liga se externfor omitido no const int global = 255;.
Evg
13

Isso é útil quando você deseja ter uma variável global. Você define as variáveis ​​globais em algum arquivo de origem e as declara externas em um arquivo de cabeçalho para que qualquer arquivo que inclua esse arquivo de cabeçalho veja a mesma variável global.

Marlon
fonte
De qualquer forma isso não soa muito OOP, eu iria colocá-los em uma única classe ... ou uma função que retorna um valor estática local ...
RZR