Odpowiedzi:
Kiedy piszesz plik realizacji ( .cpp
, .cxx
itp) kompilator generuje jednostkę tłumaczeniową . To jest plik źródłowy z twojej implementacji plus wszystkie nagłówki #include
w nim zawarte.
Powiązanie wewnętrzne odnosi się do wszystkiego tylko w zakresie jednostki tłumaczeniowej .
Zewnętrzne powiązanie odnosi się do rzeczy, które istnieją poza określoną jednostką tłumaczeniową. Innymi słowy, dostępny przez cały program , który jest kombinacją wszystkich jednostek tłumaczeniowych (lub plików obiektowych).
const
zmiennych (a także o jej cel) jest tutaj całkowicie pominięte.
Jak powiedział dudewat, zewnętrzne połączenie oznacza, że symbol (funkcja lub zmienna globalna) jest dostępny w całym programie, a wewnętrzne połączenie oznacza, że jest dostępne tylko w jednej jednostce tłumaczeniowej .
Możesz jawnie kontrolować powiązanie symbolu za pomocą słów kluczowych extern
i static
. Jeśli połączenie nie jest określone, wówczas domyślne połączenie jest extern
dla const
symboli niebędących symbolami i static
(wewnętrzne) dla const
symboli.
// 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
Zauważ, że zamiast używać static
wewnętrznego połączenia, lepiej jest używać anonimowych przestrzeni nazw, w których możesz również umieścić class
es. Łączenie anonimowych przestrzeni nazw zmieniło się między C ++ 98 i C ++ 11, ale najważniejsze jest to, że są one nieosiągalne dla innych jednostek tłumaczeniowych.
namespace {
int i; // external linkage but unreachable from other translation units.
class invisible_to_others { };
}
extern
deklarację w drugim pliku.static
. Mówi się, że takie zmienne mają wewnętrzne powiązanie .Rozważ następujący przykład:
void f(int i);
extern const int max = 10;
int n = 0;
int main()
{
int a;
//...
f(a);
//...
f(a);
//...
}
f
deklaruje się f
jako funkcję z zewnętrznym łącznikiem (domyślnie). Jego definicja musi zostać podana w dalszej części tego pliku lub w innej jednostce tłumaczeniowej (podanej poniżej).max
jest zdefiniowany jako stała całkowita. Domyślne połączenie dla stałych jest wewnętrzne . Jego powiązanie zostało zmienione na zewnętrzne za pomocą słowa kluczowego extern
. Teraz max
można uzyskać dostęp do innych plików.n
jest zdefiniowany jako zmienna całkowita. Domyślne powiązanie dla zmiennych zdefiniowanych poza ciałami funkcji jest zewnętrzne .#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;
}
max
jest zadeklarowany jako zewnętrzny link . W max
jakimś pliku musi pojawić się pasująca definicja (z zewnętrznym powiązaniem). (Jak w 1.cpp)n
jest zadeklarowany jako zewnętrzny link .z
jest zdefiniowany jako zmienna globalna z wewnętrznym sprzężeniem .nCall
określa, nCall
że jest zmienną, która zachowuje swoją wartość między wywołaniami funkcji f()
. W przeciwieństwie do zmiennych lokalnych z domyślną automatyczną klasą pamięci, nCall
będą inicjowane tylko raz na początku programu, a nie raz dla każdego wywołania f()
. Specyfikator klasy pamięci static
wpływa na czas życia zmiennej lokalnej, a nie na jej zakres.Uwaga: słowo kluczowe static
odgrywa podwójną rolę. W przypadku definicji zmiennych globalnych określa powiązanie wewnętrzne . Kiedy jest używany w definicjach zmiennych lokalnych, określa, że czas życia zmiennej ma być czasem trwania programu, a nie czasem trwania funkcji.
Mam nadzieję, że to pomaga!
static
pozwala na leniwe pojedyncze inicjowanie (co może być przydatne, jeśli potrzebujesz obiektu globalnego, ale musisz kontrolować, kiedy jest on budowany z powodu problemów z globalnym porządkiem konstrukcji i nie może dynamicznie przydzielić go używanie new
bardziej szczegółowych schematów inicjalizacji może wykraczać poza to, co jest konieczne dla danego obiektu; w konsekwencji jest to głównie problem w systemach wbudowanych korzystających z C ++).
Porozmawiajmy o innym zakresie w „C”
ZAKRES: Zasadniczo to jak długo mogę coś zobaczyć i jak daleko.
Zmienna lokalna: Zakres jest tylko wewnątrz funkcji. Znajduje się w obszarze STOSOWANIA RAM. Co oznacza, że za każdym razem, gdy funkcja jest wywoływana, wszystkie zmienne wchodzące w skład tej funkcji, w tym argumenty funkcji, są tworzone na nowo i niszczone, gdy kontrola wyjdzie z funkcji. (Ponieważ stos jest opróżniany za każdym razem, gdy funkcja powraca)
Zmienna statyczna: zakres tego dotyczy pliku. Jest dostępny w każdym miejscu pliku,
w którym został zadeklarowany. Znajduje się w segmencie danych RAM. Ponieważ można to uzyskać tylko w pliku, a tym samym połączenie wewnętrzne. Każdy
inne pliki nie widzą tej zmiennej. W rzeczywistości słowo kluczowe STATIC jest jedynym sposobem, w jaki możemy wprowadzić pewien poziom danych lub funkcji
ukrywających się w „C”
Zmienna globalna: zakres tego dotyczy całej aplikacji. Jest dostępny z każdego miejsca aplikacji. Zmienne globalne znajdują się również w segmencie DANYCH, ponieważ można uzyskać do nich dostęp w każdym miejscu aplikacji, a tym samym powiązanie zewnętrzne
Domyślnie wszystkie funkcje są globalne. W przypadku, gdy chcesz ukryć niektóre funkcje w pliku z zewnątrz, możesz poprzedzić funkcję statycznym słowem kluczowym. :-)
Zanim zaczniesz mówić o tym pytaniu, lepiej dokładnie znać termin jednostka tłumacząca , program i kilka podstawowych pojęć C ++ (tak naprawdę łączenie jest ogólnie jednym z nich). Musisz także wiedzieć, jaki jest zakres .
Podkreślę kilka kluczowych punktów, zwłaszcza. brakujące w poprzednich odpowiedziach.
Powiązanie jest właściwością nazwy , która jest wprowadzana przez deklarację . Różne nazwy mogą oznaczać ten sam byt (zazwyczaj obiekt lub funkcję). Zatem mówienie o powiązaniu jednostki jest zwykle nonsensem, chyba że masz pewność, że do jednostki będzie odwoływała się tylko unikalna nazwa z niektórych konkretnych deklaracji (zazwyczaj jednak jedna deklaracja).
Zauważ, że obiekt jest bytem, ale zmienna nim nie jest. Mówiąc o powiązaniu zmiennej, w rzeczywistości chodzi o nazwę oznaczonego bytu (wprowadzoną przez określoną deklarację). Połączenie nazwy znajduje się w jednym z trzech: brak połączenia, połączenie wewnętrzne lub połączenie zewnętrzne.
Różne jednostki tłumaczeniowe mogą współdzielić tę samą deklarację poprzez dołączenie nagłówka / pliku źródłowego (tak, to sformułowanie standardu). Możesz więc odwoływać się do tej samej nazwy w różnych jednostkach tłumaczeniowych. Jeśli zadeklarowana nazwa ma powiązanie zewnętrzne, tożsamość encji, do której odnosi się nazwa, jest również wspólna. Jeśli zadeklarowana nazwa ma powiązanie wewnętrzne, ta sama nazwa w różnych jednostkach tłumaczeniowych oznacza różne jednostki, ale można odwoływać się do jednostki w różnych zakresach tej samej jednostki tłumaczeniowej. Jeśli nazwa nie ma powiązania, po prostu nie można skierować obiektu z innych zakresów.
(Ups ... Odkryłem, że to, co wpisałem, było po prostu powtórzeniem standardowego sformułowania ...)
Istnieją również inne mylące punkty, które nie są uwzględnione w specyfikacji języka.
__attribute__
__declspec
Zasada powiązania z zakresu nazw const
zmiennej jest coś specjalnego (a szczególnie różni się od const
obiektu zadeklarowanego w zakresie plików w języku C, który ma również koncepcję powiązania identyfikatorów). Ponieważ ODR jest wymuszony przez C ++, ważne jest, aby zachować nie więcej niż jedną definicję tej samej zmiennej lub funkcji występującą w całym programie, z wyjątkiem inline
funkcji . Jeśli nie ma takiej specjalnej zasady const
, najprostsza deklaracja const
zmiennej z inicjalizatorami (np.= xxx
) W nagłówku lub pliku źródłowym (często „plik nagłówka”) zawarta w wielu jednostkach tłumaczeniowych (lub w tej samej jednostce więcej niż jeden raz, choć rzadko) w programie naruszy ODR, co sprawia, że warto go używaćconst
zmienna, ponieważ niemożliwe jest zastąpienie niektórych makr obiektowych.
Myślę, że wewnętrzne i zewnętrzne powiązania w C ++ dają jasne i zwięzłe wyjaśnienie:
Jednostka tłumacząca odnosi się do pliku implementacyjnego (.c / .cpp) i wszystkich zawartych w nim plików nagłówkowych (.h / .hpp). Jeśli obiekt lub funkcja w takiej jednostce tłumaczenia ma wewnętrzne połączenie, ten konkretny symbol jest widoczny tylko dla linkera w tej jednostce tłumaczenia. Jeśli obiekt lub funkcja ma powiązanie zewnętrzne, linker może to również zobaczyć podczas przetwarzania innych jednostek tłumaczeniowych. Statyczne słowo kluczowe użyte w globalnej przestrzeni nazw powoduje, że symbol ma wewnętrzne powiązanie. Słowo kluczowe extern powoduje, że symbol ma zewnętrzny link.
Kompilator domyślnie łączy takie symbole, że:
Niestałe zmienne globalne mają domyślnie zewnętrzne połączenie
Stałe zmienne globalne mają domyślnie wewnętrzne połączenie
Funkcje mają domyślnie zewnętrzne połączenie
Połączenie określa, czy identyfikatory o identycznych nazwach odnoszą się do tego samego obiektu, funkcji lub innej jednostki, nawet jeśli identyfikatory te występują w różnych jednostkach tłumaczeniowych. Połączenie identyfikatora zależy od tego, jak zostało zadeklarowane. Istnieją trzy rodzaje powiązań:
Tylko C ++ : możesz również mieć powiązanie między fragmentami kodu C ++ i innych niż C ++, co nazywa się łączeniem języka .
Źródło: IBM Program Linkage
Gruntownie
extern linkage
zmienna jest widoczna we wszystkich plikachinternal linkage
zmienna jest widoczna w jednym pliku.Wyjaśnij: stałe zmienne domyślnie łączą się wewnętrznie, chyba że zadeklarowano inaczej jako zewnętrzne
external linkage
const
zmienna globalna tointernal linkage
extern const
zmienna globalna toexternal linkage
Całkiem niezły materiał o linkowaniu w C ++
http://www.goldsborough.me/c/c++/linker/2016/03/30/19-34-25-internal_and_external_linkage_in_c++/
W C ++
Każda zmienna o zasięgu pliku, która nie jest zagnieżdżona w klasie lub funkcji, jest widoczna we wszystkich jednostkach tłumaczeniowych w programie. Nazywa się to łączem zewnętrznym, ponieważ w czasie łączenia nazwa jest widoczna dla łącznika wszędzie, poza jednostką tłumaczeniową.
Zmienne globalne i funkcje zwykłe mają powiązanie zewnętrzne.
Nazwa obiektu statycznego lub funkcji w zakresie pliku jest lokalna dla jednostki tłumaczącej. To się nazywa jako wewnętrzne połączenie
Powiązanie odnosi się tylko do elementów, które mają adresy w czasie łączenia / ładowania; dlatego deklaracje klas i zmienne lokalne nie są powiązane.