O que é ligação externa e ligação interna?

337

Eu quero entender a ligação externa e a conexão interna e suas diferenças.

Eu também quero saber o significado de

constvariáveis ​​vinculam internamente por padrão, a menos que seja declarado de outra forma extern.

rkb
fonte

Respostas:

278

Quando você escreve um arquivo de implementação ( .cpp, .cxx, etc) o seu compilador gera uma unidade de tradução . Este é o arquivo de origem da sua implementação, além de todos os cabeçalhos que você possui #include.

A ligação interna refere-se a tudo apenas no escopo de uma unidade de tradução .

Ligação externa refere-se a coisas que existem além de uma unidade de tradução específica. Em outras palavras, acessível por todo o programa , que é a combinação de todas as unidades de tradução (ou arquivos de objeto).

dudewat
fonte
112
Eu voto isso com exceção de uma falha: uma unidade de tradução não é "de alguma forma o arquivo de objeto", é o código fonte a partir do qual o compilador cria o arquivo de objeto.
SBI
4
@FrankHB, qual é o "algo mais importante" que falta à resposta?
Matemático
2
@ Mathematician Desculpe pelo atraso ... acho que o problema deve ser óbvio (além da precisão da redação). Essa resposta está incompleta, pois a questão sobre a regra das constvariáveis ​​(assim como sua finalidade) é totalmente esquecida aqui.
FrankHB
293

Como dudewat disse que a ligação externa significa que o símbolo (função ou variável global) está acessível em todo o programa e a conexão interna significa que ele está acessível apenas em uma unidade de tradução .

Você pode controlar explicitamente a ligação de um símbolo usando as palavras extern- staticchave e . Se a ligação não for especificada, a ligação padrão é externpara não- constsímbolos e static(interna) para constsímbolos.

// in namespace or global scope
int i; // extern by default
const int ci; // static by default
extern const int eci; // explicitly extern
static int si; // explicitly static

// the same goes for functions (but there are no const functions)
int foo(); // extern by default
static int bar(); // explicitly static 

Observe que, em vez de usar staticpara ligação interna, é melhor usar namespaces anônimos nos quais você também pode colocar classes. A ligação para namespaces anônimos mudou entre C ++ 98 e C ++ 11, mas o principal é que eles são inacessíveis a partir de outras unidades de tradução.

namespace {
   int i; // external linkage but unreachable from other translation units.
   class invisible_to_others { };
}
Motti
fonte
11
A implementação da palavra-chave "export" destacou uma diferença entre uma função declarada 'estática' e uma função declarada no espaço de nome sem nome. Para resumir da melhor maneira possível, um modelo de função declarado com a palavra-chave export em uma unidade de tradução pode se referir a uma função definida em um espaço de nome sem nome de uma unidade de tradução diferente como resultado de uma pesquisa em duas fases. ( ddj.com/showArticle.jhtml?articleID=184401584 )
Richard Corden
O que acontece se eu fizer o seguinte: 1.cpp <code> const int ci; </code> 2.cpp <code> extern const int ci; </code> #
682 Rajendra Uppal
2
@Rajenda, você receberá um erro de símbolo não resolvido (desculpe pelo atraso de nove meses em responder, perdi este comentário).
Motti
4
Informações que podem melhorar bastante esta resposta: 1) estática não é mais obsoleta no C ++ 11. 2) os membros anônimos do espaço para nome no C ++ 11 têm ligação interna por padrão. Veja stackoverflow.com/questions/10832940/…
Klaim
2
O que significa "ligação externa, mas inacessível a partir de outras unidades de tradução"? Como pode ser inacessível, mas ainda externo?
szx
101
  • Uma variável global possui ligação externa por padrão. Seu escopo pode ser estendido para arquivos que não contenham, fornecendo uma externdeclaração correspondente no outro arquivo.
  • O escopo de uma variável global pode ser restrito ao arquivo que contém sua declaração prefixando a declaração com a palavra-chave static. Diz-se que essas variáveis ​​têm ligação interna .

Considere o seguinte exemplo:

1.cpp

void f(int i);
extern const int max = 10;
int n = 0;
int main()
{
    int a;
    //...
    f(a);
    //...
    f(a);
    //...
}
  1. A assinatura da função fdeclara fcomo uma função com ligação externa (padrão). Sua definição deve ser fornecida posteriormente neste arquivo ou em outra unidade de tradução (fornecida abaixo).
  2. maxé definido como uma constante inteira. A ligação padrão para constantes é interna . Sua ligação é alterada para externo com a palavra-chave extern. Então agora maxpode ser acessado em outros arquivos.
  3. né definido como uma variável inteira. A ligação padrão para variáveis ​​definidas fora dos corpos das funções é externa .

2.cpp

#include <iostream>
using namespace std;

extern const int max;
extern int n;
static float z = 0.0;

void f(int i)
{
    static int nCall = 0;
    int a;
    //...
    nCall++;
    n++;
    //...
    a = max * z;
    //...
    cout << "f() called " << nCall << " times." << endl;
}
  1. maxé declarado como tendo ligação externa . Uma definição correspondente para max(com ligação externa) deve aparecer em algum arquivo. (Como em 1.cpp)
  2. né declarado como tendo ligação externa .
  3. zé definido como uma variável global com ligação interna .
  4. A definição de nCallespecifica nCallser uma variável que retém seu valor entre as chamadas à função f(). Diferentemente das variáveis ​​locais com a classe de armazenamento automático padrão, nCallserão inicializadas apenas uma vez no início do programa e não uma vez para cada chamada de f(). O especificador de classe de armazenamento staticafeta o tempo de vida da variável local e não seu escopo.

NB: A palavra-chave staticdesempenha um papel duplo. Quando usado nas definições de variáveis ​​globais, especifica a ligação interna . Quando usado nas definições das variáveis ​​locais, especifica que o tempo de vida da variável será a duração do programa, em vez de ser a duração da função.

Espero que ajude!

Rajendra Uppal
fonte
2
É importante ressaltar que, quando usado nas definições de variáveis ​​locais, staticpermite uma inicialização lenta e lenta (o que pode ser útil se você precisar de um objeto global, mas precisar controlar quando ele é construído devido a problemas com a ordem de construção global e não pode alocá-lo dinamicamente) o uso de newesquemas de inicialização mais detalhados pode estar além do necessário para o objeto em questão; por implicação, isso é principalmente um problema em sistemas incorporados que usam C ++).
JAB
11
Muito bom Examle, fez o meu dia.
Blood-HaZaRd 03/06/19
28

Em termos de 'C' (como a palavra-chave estática tem um significado diferente entre 'C' e 'C ++')

Vamos falar sobre escopo diferente em 'C'

ESCOPO: É basicamente quanto tempo posso ver alguma coisa e até que ponto.

  1. Variável local: o escopo está apenas dentro de uma função. Ele reside na área PILHA da RAM. O que significa que toda vez que uma função é chamada, todas as variáveis ​​que fazem parte dessa função, incluindo argumentos de função, são criados recentemente e são destruídos quando o controle sai da função. (Como a pilha é liberada toda vez que a função retorna)

  2. Variável estática: o escopo é para um arquivo. É acessível em qualquer lugar do arquivo
    em que é declarado. Ele reside no segmento de dados da RAM. Como isso só pode ser acessado dentro de um arquivo e, portanto, ligação interna. Quaisquer
    outros arquivos não podem ver esta variável. De fato, a palavra-chave STATIC é a única maneira pela qual podemos introduzir algum nível de dados ou função
    ocultos em 'C'

  3. Variável global: o escopo é para um aplicativo inteiro. É um formulário acessível em qualquer lugar do aplicativo. Variáveis ​​globais também residem no segmento DATA, pois podem ser acessadas em todos os lugares do aplicativo e, portanto, EXTERNAL Linkage

Por padrão, todas as funções são globais. Caso precise ocultar algumas funções de um arquivo de fora, você pode prefixar a palavra-chave estática na função. :-)

Libin Jose
fonte
12
@Libin: Quanto a 1) variáveis ​​locais não precisam estar na pilha - elas geralmente estão na pilha, mas podem estar em registradores e, no ambiente ARM, estão mais frequentemente em registradores do que na pilha (depende de alguns fatores - nível de chamada, número de argumentos formais ..)
Artur
4
@Libin: Quanto a 1) Se você considerar 'flush' como substituição - isso está errado. O ponteiro da pilha é apenas movido para um local diferente. Nenhum 'local local válido anteriormente' é 'liberado' / limpo etc. Você mistura o escopo variável com a duração do armazenamento. O escopo informa de onde você pode acessar uma var. A duração do armazenamento informa quanto tempo ela existe. Você pode ter variável local com duração de armazenamento estático. Isso significa que ele vive "para sempre", mas pode ser acessado a partir de uma função é declarada no.
Artur
2
Voto negativo para conceitos imprecisos e equívocos óbvios. Estritamente falando, não há "global" nem "variável" (como um substantivo) definido em C. Você provavelmente pode querer referir "objeto de escopo de arquivo" em vez de "variável global", mas falar em "escopo" (em C é uma propriedade de um identificador ) disso é um absurdo. (Ambos os termos são definidos no C ++ normatively com significados ligeiramente diferentes.)
FrankHB
@Artur Acho que você esqueceu o " único " em " Significa que ele vive" para sempre ", mas pode ser acessado (apenas) a partir de uma função na qual é declarado. " - Este é um detalhe importante, portanto, gostaria de apontar isso explicitamente.
RobertS apoia Monica Cellio
11
@RobertSsupportsMonicaCellio - você está certo
Artur
14

Antes de falar sobre a questão, é melhor conhecer o termo unidade de tradução , programa e alguns conceitos básicos de C ++ (na verdade, linkage é um deles em geral) com precisão. Você também precisará saber o que é um escopo .

Vou enfatizar alguns pontos-chave, esp. aqueles que faltam nas respostas anteriores.

Linkage é uma propriedade de um nome , que é introduzida por uma declaração . Nomes diferentes podem denotar a mesma entidade (normalmente, um objeto ou uma função). Portanto, falar sobre vinculação de uma entidade geralmente não faz sentido, a menos que você tenha certeza de que a entidade será referida apenas pelo nome exclusivo de algumas declarações específicas (geralmente uma declaração).

Observe que um objeto é uma entidade, mas uma variável não é. Ao falar sobre o vínculo de uma variável, na verdade o nome da entidade denotada (que é introduzida por uma declaração específica) está em causa. O vínculo do nome está em um dos três: nenhum vínculo, vínculo interno ou vínculo externo.

Unidades de tradução diferentes podem compartilhar a mesma declaração por inclusão no cabeçalho / arquivo de origem (sim, é o texto da norma). Portanto, você pode consultar o mesmo nome em diferentes unidades de tradução. Se o nome declarado tiver ligação externa, a identidade da entidade referida pelo nome também será compartilhada. Se o nome declarado tiver ligação interna, o mesmo nome em diferentes unidades de conversão denota entidades diferentes, mas você pode consultá-la em escopos diferentes da mesma unidade de conversão. Se o nome não tiver vínculo, você simplesmente não poderá consultar a entidade de outros escopos.

(Opa ... Eu achei que o que eu digitei estava apenas repetindo o texto padrão ...)

Existem também outros pontos confusos que não são cobertos pela especificação da linguagem.

  1. Visibilidade (de um nome). É também uma propriedade de nome declarado, mas com um significado diferente para o vínculo .
  2. Visibilidade (de um efeito colateral) . Isso não está relacionado a este tópico.
  3. Visibilidade (de um símbolo). Essa noção pode ser usada por implementações reais . Nessas implementações, um símbolo com visibilidade específica no código do objeto (binário) geralmente é o destino mapeado a partir da definição da entidade cujos nomes têm a mesma ligação específica no código de origem (C ++). No entanto, geralmente não é garantido individualmente. Por exemplo, um símbolo em uma imagem de biblioteca dinâmica pode ser especificado apenas compartilhado internamente nessa imagem a partir do código-fonte (envolvido em algumas extensões, normalmente __attribute__ou__declspec) ou opções do compilador, e a imagem não é o programa inteiro ou o arquivo de objeto traduzido de uma unidade de tradução; portanto, nenhum conceito padrão pode descrevê-lo com precisão. Como símbolo não é um termo normativo em C ++, é apenas um detalhe de implementação, mesmo que as extensões relacionadas de dialetos possam ter sido amplamente adotadas.
  4. Acessibilidade. No C ++, geralmente trata-se de propriedade de membros da classe ou classes base , que é novamente um conceito diferente, não relacionado ao tópico.
  5. Global. No C ++, "global" refere-se a algo do espaço para nome global ou do escopo do espaço para nome global. O último é aproximadamente equivalente ao escopo do arquivo na linguagem C. Tanto em C como em C ++, a ligação não tem nada a ver com escopo, embora o escopo (como a vinculação) também esteja fortemente relacionado a um identificador (em C) ou a um nome (em C ++) introduzido por alguma declaração.

A regra de ligação da constvariável de escopo do espaço para nome é algo especial (e particularmente diferente do constobjeto declarado no escopo do arquivo na linguagem C, que também possui o conceito de ligação de identificadores). Como o ODR é imposto pelo C ++, é importante manter não mais de uma definição da mesma variável ou função ocorrida em todo o programa, exceto as inlinefunções . Se não houver essa regra especial const, uma declaração mais simples de constvariável com inicializadores (por exemplo = xxx) em um cabeçalho ou arquivo de origem (geralmente um "arquivo de cabeçalho") incluído por várias unidades de tradução (ou incluídas por uma unidade de tradução mais de uma vez, embora raramente) em um programa viole o ODR, o que faz com queconst variável como substituição de algumas macros do tipo objeto.

FrankHB
fonte
3
Essa resposta parece muito proficiente e pode ser muito exata (não posso julgar isso), mas provavelmente não é tão compreensível quanto desejado por muitas pessoas que pesquisam essa pergunta aqui, em vez de lerem diretamente as especificações do idioma. Pelo menos para minhas necessidades, continuarei com a resposta aceita, mas ainda assim obrigado por fornecer uma pequena visão sobre as especificações de idioma. 👍🏻
wedi
8

Eu acho que a ligação interna e externa em C ++ fornece uma explicação clara e concisa:

Uma unidade de conversão refere-se a um arquivo de implementação (.c / .cpp) e a todos os arquivos de cabeçalho (.h / .hpp) que ele inclui. Se um objeto ou função dentro de uma unidade de conversão tiver ligação interna, esse símbolo específico será visível apenas para o vinculador dentro dessa unidade de conversão. Se um objeto ou função tiver ligação externa, o vinculador também poderá vê-lo ao processar outras unidades de conversão. A palavra-chave estática, quando usada no espaço para nome global, força um símbolo a ter ligação interna. A palavra-chave extern resulta em um símbolo com ligação externa.

O compilador padroniza a ligação de símbolos, de modo que:

Variáveis ​​globais não const têm ligação externa por padrão
Variáveis ​​globais const têm conexão interna por padrão
Funções têm ligação externa por padrão

Nan Xiao
fonte
6

A ligação determina se os identificadores com nomes idênticos se referem ao mesmo objeto, função ou outra entidade, mesmo que esses identificadores apareçam em unidades de conversão diferentes. A ligação de um identificador depende de como foi declarado. Existem três tipos de ligações:

  1. Ligação interna : identificadores só podem ser vistos em uma unidade de tradução.
  2. Ligação externa : identificadores podem ser vistos (e referidos) em outras unidades de tradução.
  3. Sem vínculo : identificadores só podem ser vistos no escopo em que estão definidos. A ligação não afeta o escopo

Apenas C ++ : você também pode ter vínculo entre fragmentos de código C ++ e não C ++, que é chamado de vínculo de idioma .

Fonte: IBM Program Linkage

Arun Pal
fonte
5

Basicamente

  • extern linkage variável é visível em todos os arquivos
  • internal linkage A variável é visível em um único arquivo.

Explicar: variáveis ​​const vinculadas internamente por padrão, a menos que declaradas de outra forma como externas

  1. Por padrão, a variável global é external linkage
  2. mas, constvariável global éinternal linkage
  3. extern constvariável global extra éexternal linkage

Um material muito bom sobre ligação em C ++

http://www.goldsborough.me/c/c++/linker/2016/03/30/19-34-25-internal_and_external_linkage_in_c++/

Cor
fonte
1

Em C ++

Qualquer variável no escopo do arquivo e que não esteja aninhada dentro de uma classe ou função, é visível em todas as unidades de tradução em um programa. Isso é chamado de ligação externa porque, no momento do link, o nome fica visível para o vinculador em qualquer lugar, externo a essa unidade de tradução.

Variáveis ​​globais e funções comuns têm ligação externa.

O objeto estático ou o nome da função no escopo do arquivo é local para a unidade de conversão. Isso é chamado de ligação interna

Vinculação refere-se apenas a elementos que possuem endereços no momento do link / carregamento; portanto, declarações de classe e variáveis ​​locais não têm ligação.

Saurabh Raoot
fonte
Vars globais const têm ligação interna.
Blood-HaZaRd 30/01/19