Dış bağlantı ve iç bağlantı nedir?


337

Dış bağlantıyı ve iç bağlantıyı ve farklılıklarını anlamak istiyorum.

Ayrıca anlamını bilmek istiyorum

constdeğişkenler aksi belirtilmedikçe dahili olarak varsayılan olarak bağlantı verir extern.

Yanıtlar:


279

Eğer (bir uygulama dosyası yazarken .cpp, .cxx, vb) derleyici bir oluşturur çeviri birimi . Bu, uygulamanızın kaynak dosyası ve içinde oluşturduğunuz tüm üstbilgilerdir #include.

İç bağlantı , yalnızca bir çeviri birimi kapsamındaki her şeyi ifade eder .

Dış bağlantı , belirli bir çeviri biriminin ötesinde olan şeyleri ifade eder. Başka bir deyişle, tüm çeviri birimlerinin (veya nesne dosyalarının) birleşimi olan tüm program aracılığıyla erişilebilir .


112
Ben bir aksaklık dışında bu upvote: Bir çeviri birimi "bir şekilde nesne dosyası" değil, derleyici nesne dosyasını oluşturur kaynak kodu .
sbi

4
@FrankHB, cevabın eksik olduğu "daha önemli bir şey" nedir?
Matematikçi

2
@Mathematician Geç kaldığım için üzgünüm ... Sorunun açık olması gerektiğini düşünüyorum (ifadelerin doğruluğunun yanı sıra). Bu cevap, constdeğişkenlerin kuralı (ve amacının yanı sıra) hakkındaki soru burada tamamen eksik olduğu için eksiktir .
FrankHB

294

As dudewat söyledi harici bağlantı simgesi (işlev veya global değişken) programınızın ve tamamında mevcuttur demektir bunun tek tek erişilebilir olduğundan bağlantı araçlarının çeviri birimi .

Açıkça kullanarak bir sembolün bağlantıyı kontrol edebilir externve staticanahtar kelimeleri. Bağlantı belirtilmezse, varsayılan bağlantı sembol olmayanlar ve semboller externiçin (dahili) içindir .conststaticconst

// 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 

staticİç bağlantı için kullanmak yerine, es yerleştirebileceğiniz anonim ad alanlarını kullanmak daha iyidir class. Anonim ad alanları için bağlantı C ++ 98 ve C ++ 11 arasında değişmiştir, ancak asıl önemli olan diğer çeviri birimlerinden erişilememesidir.

namespace {
   int i; // external linkage but unreachable from other translation units.
   class invisible_to_others { };
}

11
"Export" anahtar sözcüğünün uygulanması, 'statik' olarak adlandırılan bir işlev ile adsız ad alanında bildirilen bir işlev arasında bir fark olduğunu vurguladı. Elimden geldiğince özetlemek gerekirse, bir çeviri biriminde export anahtar sözcüğü ile bildirilen bir işlev şablonu, 2 aşamalı arama sonucunda farklı bir çeviri biriminin adsız ad alanında tanımlanan bir işleve başvurabilir. ( ddj.com/showArticle.jhtml?articleID=184401584 )
Richard Corden

Aşağıdakileri yaparsam: 1.cpp <code> const int ci; </code> 2.cpp <code> extern const int ci; </code>
Rajendra Uppal

2
@Rajenda, çözülmemiş bir sembol hatası alacaksınız (cevaplamadaki dokuz aylık gecikme için özür dilerim) Bu yorumu kaçırdım.
Motti

4
Bu cevabı büyük ölçüde artırabilecek bilgiler: 1) statik C ++ 11'de artık kullanılmıyor. 2) C ++ 11'deki anonim ad alanı üyeleri varsayılan olarak dahili bağlantıya sahiptir. Bkz. Stackoverflow.com/questions/10832940/…
Klaim

2
"Harici bağlantı ancak diğer çeviri birimlerinden erişilemeyen" ne anlama geliyor? Nasıl ulaşılamaz ancak hala dışsal olabilir?
szx

101
  • Genel değişken varsayılan olarak harici bağlantıya sahiptir . Kapsamı extern, diğer dosyada eşleşen bir bildiri vererek içerdiği dosyalara genişletilebilir .
  • Genel bir değişkenin kapsamı, bildirime anahtar kelime ile ön ek eklenerek bildirimini içeren dosya ile sınırlandırılabilir static. Bu değişkenlerin iç bağlantıya sahip olduğu söylenir .

Aşağıdaki örneği düşünün:

1.cpp

void f(int i);
extern const int max = 10;
int n = 0;
int main()
{
    int a;
    //...
    f(a);
    //...
    f(a);
    //...
}
  1. Fonksiyonun imza fbeyan file bir fonksiyonu olarak dış bağlantı (varsayılan). Tanımı bu dosyada veya başka bir çeviri biriminde (aşağıda verilmiştir) belirtilmelidir.
  2. maxbir tamsayı sabiti olarak tanımlanır. Sabitleri için varsayılan bağlantı olduğunu dahili . Bağlantısı anahtar kelimeyle harici olarak değiştirilir extern. Artık maxbaşka dosyalardan da erişilebilir.
  3. nbir tamsayı değişkeni olarak tanımlanır. İşlev gövdelerinin dışında tanımlanan değişkenler için varsayılan bağlantı harici değerdir .

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. maxdış bağlantıya sahip olduğu beyan edilmiştir . maxBazı dosyalarda (harici bağlantıyla) için eşleşen bir tanım görünmelidir. (1.cpp'de olduğu gibi)
  2. ndış bağlantıya sahip olduğu beyan edilmiştir .
  3. zolduğu belirlenen bir küresel değişken olarak iç bağlantı .
  4. İşlevi'nin tanımı, işlev çağrıları boyunca değerini koruyan bir değişken olduğunu nCallbelirtir . Varsayılan otomatik depolama sınıfına sahip yerel değişkenlerin aksine, her çağırma için bir kez değil, programın başında bir kez başlatılır . Depolama sınıfı belirticisi kapsamını değil, yerel değişkenin ömrünü etkiler.nCallf()nCallf()static

Not: Anahtar kelime staticçift ​​rol oynar. Global değişkenlerin tanımlarında kullanıldığında, iç bağlantıyı belirtir . Yerel değişkenlerin tanımlarında kullanıldığında, değişkenin ömrünün işlevin süresi olmak yerine programın süresi olacağını belirtir.

Umarım yardımcı olur!


2
Önemli olarak, yerel değişkenlerin tanımlarında kullanıldığında static, tembel tek başlatmaya izin verir (global-ish nesnesine ihtiyacınız varsa yararlı olabilir, ancak global inşaat siparişi ile ilgili sorunlar nedeniyle ne zaman inşa edildiğini kontrol etmek zorunda kalır ve dinamik olarak ayıramazsınız kullanarak newima yolu ile bu) C ++ kullanmak gömülü sistemlerde bir sorun esas olduğu; daha derinlemesine başlatma düzenleri söz konusu nesne için gerekenin ötesine olabileceği görüşündedir.
JAB

1
Very Good Examle, benim günümü yaptı.
Blood-HaZaRd

28

'C' açısından (Statik anahtar kelimenin 'C' ve 'C ++' arasında farklı bir anlamı olduğundan)

'C' de farklı kapsam hakkında konuşalım

KAPSAM: Temelde bir şeyi ne kadar süreyle ve ne kadar uzağa görebiliyorum.

  1. Yerel değişken: Kapsam yalnızca bir işlevin içindedir. RAM'in STACK alanında bulunur. Bu, bir işlev her çağrıldığında, işlev bağımsız değişkenleri de dahil olmak üzere o işlevin parçası olan tüm değişkenler yeni oluşturulur ve denetim işlevden çıktıktan sonra yok edilir. (İşlev her döndüğünde yığın temizlendiğinden)

  2. Statik değişken: Bunun kapsamı bir dosya içindir. Dosyaya
    bildirildiği her yerde erişilebilir . RAM'in VERİ bölümünde bulunur. Bu, yalnızca bir dosya içinde erişilebilir ve bu nedenle DAHİLİ bağlantı. Herhangi
    diğer dosyaları bu değişkeni göremez. Aslında STATIC anahtar sözcüğü,
    'C' de gizlenen bir miktar veri veya işlev sunmanın tek yoludur.

  3. Global değişken: Bunun kapsamı tüm bir uygulama içindir. Uygulamanın her yerine erişilebilir bir formdur. Global değişkenler DATA segmentinde de bulunur, çünkü uygulamadaki her yere ve dolayısıyla EXTERNAL Linkage'a erişilebilir.

Varsayılan olarak tüm işlevler globaldir. Bir dosyadaki bazı işlevleri dışarıdan gizlemeniz gerekirse, statik anahtar kelimeyi işleve önek olarak ekleyebilirsiniz. :-)


12
@Libin: 1'e gelince, yerel değişkenler yığın üzerinde olmak zorunda değildir - genellikle yığın üzerindedir, ancak yazmaçlarda olabilir ve ARM ortamında kayıtlarda yığından daha sıktırlar (bazı faktörlere bağlıdır - çağrı seviyesi, sayı resmi args ..)
Artur

4
@Libin: 1'e gelince) Eğer 'floş'u' üzerine yazmayı düşünüyorsanız - bu yanlıştır. Yığın işaretçisi farklı bir yere taşındı. 'Önceden geçerli yerel değişkenler' 'temizlenir' / silinmez vb. Değişken kapsamı depolama süresi ile karıştırırsınız. Kapsam, bir var. Depolama süresi ne kadar süreceğini gösterir. Statik depolama süresine sahip yerel değişkeniniz olabilir. Bu "sonsuza kadar" yaşadığı anlamına gelir, ancak bildirildiği bir işlevden erişilebilir.
Artur

2
Yanlış kavramlar ve bariz yanılgılar için aşağıya oy verin. Açıkçası, C'de tanımlanmış bir "global" veya "değişken" (isim olarak) yoktur. Muhtemelen "global değişken" yerine "dosya kapsamı nesnesine" atıfta bulunmak, ancak "scope" (C bir tanımlayıcının özelliğidir ) saçmalıktır. (Her iki terim de C ++ 'da normatif olarak biraz farklı anlamlarla tanımlanmıştır.)
FrankHB

@Artur Sanırım " sadece " in " sonsuza kadar yaşadığı anlamına gelir " ini unutmuşsunuzdur, ancak (sadece) bildirildiği bir işlevden erişilebilir. "- Bu önemli bir ayrıntıdır, bu yüzden işaret etmek istiyorum açıkça.
RobertS

14

Soru hakkında konuşmadan önce, çeviri birimi , program ve C ++ ile ilgili bazı temel kavramları (aslında bağlantı genel olarak bunlardan biridir) bilmek daha iyidir . Ayrıca kapsamın ne olduğunu da bilmeniz gerekir .

Bazı önemli noktaları vurgulayacağım, özellikle. önceki cevaplarda eksik olanlar.

Bağlantı , bir bildiriyle tanıtılan bir adın özelliğidir . Farklı adlar aynı varlığı (genellikle bir nesne veya işlev) gösterebilir . Dolayısıyla , bir varlığın bağlantısı hakkında konuşmak genellikle saçmalıktır, eğer varlığın sadece bazı belirli beyanlardan (genellikle bir beyan olsa da) benzersiz adıyla bahsedileceğinden emin değilseniz.

Bir nesnenin bir varlık olduğunu, ancak bir değişkenin olmadığını unutmayın. Bir değişkenin bağlantısı hakkında konuşurken, aslında belirtilen varlığın adı (belirli bir bildirimle tanıtılan) söz konusudur. İsmin bağlantısı üçünden birindedir: bağlantı, iç bağlantı veya dış bağlantı yok.

Farklı çeviri birimleri, aynı bildirimi başlık / kaynak dosyasıyla (evet, standardın ifadesidir) ekleyerek paylaşabilir. Böylece aynı adı farklı çeviri birimlerinde ifade edebilirsiniz. Bildirilen adın harici bir bağlantısı varsa, adla belirtilen varlığın kimliği de paylaşılır. Bildirilen adın iç bağlantısı varsa, farklı çeviri birimlerinde aynı ad farklı varlıkları ifade eder, ancak aynı çeviri biriminin farklı kapsamlarındaki varlığı ifade edebilirsiniz. Adda bağlantı yoksa, varlığı diğer kapsamlardan yönlendiremezsiniz.

(Hata ... Yazdığım şeyin standart ifadeleri tekrarlamak olduğunu gördüm ...)

Dil spesifikasyonu kapsamında olmayan bazı kafa karıştırıcı noktalar da vardır.

  1. Görünürlük (bir adın). Aynı zamanda beyan edilen bir özelliktir, ancak bağlantıdan farklı bir anlama sahiptir .
  2. Görünürlük (bir yan etkinin) . Bu konu ile ilgili değil.
  3. Görünürlük (bir sembolün). Bu kavram gerçek uygulamalar tarafından kullanılabilir . Bu tür uygulamalarda, nesne (ikili) kodunda belirli görünürlüğe sahip bir sembol genellikle adları kaynak (C ++) kodunda aynı özel bağlantıya sahip varlık tanımından eşlenen hedeftir. Ancak, genellikle bire bir garanti edilmez. Örneğin, dinamik bir kütüphane görüntüsünde bir sembol yalnızca bu görüntüde kaynak koddan dahili olarak paylaşılabilir (bazı uzantılarla, genellikle __attribute__veya__declspec) veya derleyici seçeneklerini kullanırsanız ve görüntü bir çeviri biriminden çevrilen programın tamamı veya nesne dosyası değildir, dolayısıyla hiçbir standart kavram bunu doğru bir şekilde tanımlayamaz. Sembol, C ++ 'da normatif bir terim olmadığından, lehçelerin ilgili uzantıları yaygın olarak benimsenmiş olsa bile, sadece bir uygulama detayıdır.
  4. Ulaşılabilirlik. C ++ 'da, bu genellikle konu ile ilgisi olmayan farklı bir kavram olan sınıf üyelerinin veya temel sınıfların özelliği ile ilgilidir .
  5. Küresel. C ++ 'da "global", genel ad alanı veya genel ad alanı kapsamı anlamına gelir. İkincisi, C dilinde dosya kapsamına kabaca eşdeğerdir . Hem C hem de C ++ 'da, bağlantının kapsamla hiçbir ilgisi yoktur, ancak kapsam (bağlantı gibi) de bir tanımlayıcıyla (C'de) veya bir tanımla eklenen bir adla (C ++'da) sıkı bir şekilde ilgilidir.

Ad kapsamı içinde bağlantı kuralı constdeğişkeni özel bir şey (ve özellikle farklıdır constayrıca tanımlayıcılar bağlantı kavramı vardır C dilinde dosya kapsamında beyan edilen nesne). Yana ODR C tarafından zorlanır ++ hiçbir daha fazla aynı değişken veya fonksiyonunun bir tanım daha devam hariç tüm program oluştu önemlidir inlinefonksiyonları . Böyle özel bir kural yoksa, birden çok çeviri biriminin içerdiği (veya bir çeviri birimi tarafından birden çok kez dahil edilen) bir başlıkta veya kaynak dosyada (genellikle bir "başlık dosyası") başlatıcıları constolan en basit constdeğişken bildirimi (örn. = xxx), nadiren de olsa) bir programda ODR'yi ihlal eder, bu daconst Değişken olarak bazı nesne benzeri makroların değiştirilmesi mümkün değildir.


3
Bu cevap çok yetkin ve çok kesin olabilir (bunu yargılayamıyorum), ancak büyük olasılıkla, doğrudan buradaki dil spekülasyonunu okumak yerine, bu soruyu arayan birçok insanın istediği kadar anlaşılır değildir. En azından ihtiyaçlarım için kabul edilen cevaba sadık kalacağım ama yine de dil spesifikasyonu hakkında küçük bir fikir verdiğiniz için teşekkür ederim. --🏻
wedi

8

Bence C İç ve Dış Bağlantı ++ açık ve özlü bir açıklama verir:

Bir çeviri birimi bir uygulama (.c / .cpp) dosyasına ve içerdiği tüm başlık (.h / .hpp) dosyalarına karşılık gelir. Böyle bir çeviri biriminin içindeki bir nesne ya da işlev dahili bağlantıya sahipse, o sembol yalnızca o çeviri birimindeki bağlayıcı tarafından görülebilir. Bir nesnenin veya fonksiyonun harici bağlantısı varsa, bağlayıcı diğer çeviri birimlerini işlerken de görebilir. Statik anahtar kelime, genel ad alanında kullanıldığında, bir sembolü dahili bağlantıya sahip olmaya zorlar. Extern anahtar sözcüğü, dış bağlantıya sahip bir sembolle sonuçlanır.

Derleyici, sembollerin bağlantısını varsayılan olarak ayarlar:


Sabit olmayan global değişkenler varsayılan olarak harici bağlantıya sahiptir Sabit küresel değişkenler varsayılan olarak dahili bağlantıya
sahiptir İşlevler varsayılan olarak harici bağlantıya sahiptir


6

Bağlantı, aynı adlara sahip tanımlayıcıların, bu tanımlayıcılar farklı çeviri birimlerinde görünse bile aynı nesneyi, işlevi veya başka bir varlığı ifade edip etmediğini belirler. Bir tanımlayıcının bağlantısı, nasıl bildirildiğine bağlıdır. Üç tür bağlantı vardır:

  1. İç bağlantı : tanımlayıcılar yalnızca bir çeviri biriminde görülebilir.
  2. Dış bağlantı : tanımlayıcılar diğer çeviri birimlerinde görülebilir (ve bunlara atıf yapılabilir).
  3. Bağlantı yok : tanımlayıcılar yalnızca tanımlandıkları kapsamda görülebilir. Bağlantı, kapsam belirlemeyi etkilemez

Yalnızca C ++ : C ++ ve C ++ olmayan kod parçaları arasında bağlantı olabilir, buna dil bağlantısı denir .

Kaynak: IBM Program Bağlantısı


5

temel olarak

  • extern linkage değişken tüm dosyalarda görünür
  • internal linkage değişkeni tek dosyada görülebilir.

Açıklayın: const değişkenleri, başka türlü extern olarak bildirilmedikçe varsayılan olarak dahili olarak bağlanır

  1. varsayılan olarak global değişken external linkage
  2. ancak constglobal değişkeninternal linkage
  3. ekstra, extern constglobal değişkenexternal linkage

C ++ 'da bağlantı hakkında oldukça iyi bir malzeme

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


1

C ++ dilinde

Dosya kapsamındaki ve bir sınıf veya işlevin içinde yuvalanmayan tüm değişkenler, bir programdaki tüm çeviri birimlerinde görülebilir. Buna harici bağlantı denir, çünkü bağlantı sırasında ad her yerde bu çeviri biriminin dışındaki bağlayıcı tarafından görülebilir.

Global değişkenler ve sıradan fonksiyonlar dış bağlantıya sahiptir.

Dosya kapsamındaki statik nesne veya işlev adı, çeviri biriminde yereldir. Buna İç Bağlantı denir

Bağlantı yalnızca bağlantı / yükleme zamanında adresleri olan öğeleri ifade eder; bu nedenle, sınıf bildirimleri ve yerel değişkenlerin bağlantısı yoktur.


const global değişkenler iç bağlantıya sahiptir.
Blood-HaZaRd
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.