C ++ 'da extern ne zaman kullanılır?


398

"Think in C ++" okuyorum ve sadece externbeyanı tanıttı . Örneğin:

extern int x;
extern float y;

Sanırım anlamını anlıyorum (tanımsız beyan), ama ne zaman yararlı olduğunu merak ediyorum.

Birisi örnek verebilir mi?


1
externBirkaç kez bir tanım sağlamak zorunda kaldım . Microsoft araçları, başka bir kaynak dosyadaki tablolar yalnızca tanımlandığında eksik semboller için bir bağlantı hatası üretti. Sorun, tablo oldu constve C ++ derleyici bunu staticçeviri birimine yükseltti . Bkz . Örneğin, ariatab.cppve kalynatab.cpp.
jww

2
Ve bence Nik'in cevabı doğru, çünkü C ++ sorusuna cevap veren tek kişi o. Diğer herkes bir C sorusuna yönelmiş gibi görünüyor.
jww

Yanıtlar:


519

Global değişkenleriniz olduğunda bu yararlı olur. Sen beyan varlığını başlığını içeren her kaynak dosyası bunu biliyor böylece, bir başlıkta küresel değişkenler, ama yalnızca bir kez kaynak dosyalarından birini kullanarak “define” gerekir.

Netleştirmek için, kullanan extern int x;türünde bir nesne olduğu derleyici söyler intdenilen xvar bir yerlerde . Nerede olduğunu bilmek derleyicilerin işi değil, sadece türünü ve adını bilmesi gerekir, böylece nasıl kullanılacağını bilir. Tüm kaynak dosyalar derlendikten sonra, linker xderlenen kaynak dosyalardan birinde bulduğu tanımın tüm referanslarını çözecektir . Çalışması için, xdeğişken tanımının “harici bağlantı” olarak adlandırılan şeye sahip olması gerekir, bu da temel olarak bir işlevin dışında (genellikle “dosya kapsamı” olarak adlandırılır) ve staticanahtar sözcük olmadan bildirilmesi gerektiği anlamına gelir .

başlık:

#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

kaynak 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();
}

kaynak 2:

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

void print_global_x()
{
    //print global_x here:
    std::cout << global_x << std::endl;
}

15
Teşekkür ederim. Yani, extern anahtar sözcüğü olmayan bir başlık dosyasında genel bir değişken bildirirsem, başlığı içeren kaynak dosyaları görmez mi?
Aslan986

23
bir başlıktaki global değişkenleri bildirmemelisiniz, çünkü 2 dosya aynı başlık dosyasını içerdiğinde bağlantı oluşturmaz (linker "yinelenen sembol" hakkında bir hata verir)
kuba

63
@ Aslan986: Hayır, daha kötü bir şey olur. Başlığı içeren her kaynak dosya kendi değişkenine sahip olacaktır , bu nedenle her kaynak dosya bağımsız olarak derlenecektir, ancak iki kaynak dosya aynı global tanımlayıcılara sahip olacağından bağlayıcı şikayet edecektir.
dreamlax

7
"Extern" kelimesini kullanmadığınızda, değişken değişkendir. "Extern" kullandığınızda, "hey bu başka bir yerde var var". Bu bir tanım veya bildirim olup olmadığını cevaplamadığım için üzgünüm, çünkü bu ikisi hakkında hep kafam karıştı.
kuba

3
@CCJ: Include Guard yalnızca onu içeren kaynak dosya için çalışır. Aynı başlığın aynı kaynak dosyaya iki kez dahil edilmesini durdurur (diğer başlıklar da dahil etmesi durumunda). Bu nedenle, içerme korumalarıyla bile, üstbilgiyi içeren her kaynak dosyanın yine de kendi tanımı olacaktır.
dreamlax

172

Birkaç modül arasında bir değişkeni paylaştığınızda kullanışlıdır. Bir modülde tanımlarsınız ve diğerlerinde extern kullanırsınız.

Örneğin:

file1.cpp dosyasında:

int global_int = 1;

file2.cpp dosyasında:

extern int global_int;
//in some function
cout << "global_int = " << global_int;

39
Bu cevap, kabul edileninden daha doğrudur, çünkü başlık dosyasını kullanmaz ve sadece birkaç modül arasında paylaşım yaparken faydalı olduğunu açıkça belirtir. Daha büyük uygulamalar için örneğin ConfigManager sınıfı kullanmak daha iyidir.
Zac

1
İsim alanları söz konusu olduğunda global_int, global isim alanında herhangi bir gotchas var mı? ienamespace XYZ{ void foo(){ ::global_int++ } };
jxramos

8
@Zac: Öte yandan, bir başlıkta genel bir değişken bildirmeyerek, yanlışlıkla nerede tanımlandığını belirlemeyi çok daha zor hale getirdiniz. Genellikle bir global değişkenin bildirildiğini görürseniz abc.h, bunun tanımlanması için iyi bir şans vardır abc.cpp. İyi bir IDE her zaman yardımcı olacaktır, ancak iyi organize edilmiş kod her zaman daha iyi bir çözümdür.
dreamlax

externfile2.cpp içinde olmadan , global_intsonra dahil sonra erişebilirsiniz . neden ona ihtiyacım var?
TomSawyer

62

Her şey bağlantıyla ilgili .

Önceki cevaplar hakkında iyi açıklamalar sağlamıştır extern.

Ama önemli bir nokta eklemek istiyorum.

Sen hakkında sormak externiçinde C ++ değil de C ve ne zaman dava hakkında söz cevabı yok neden bilmiyorum externile gelir constC ++.

C ++ 'da, bir constdeğişken varsayılan olarak dahili bağlantıya sahiptir (C gibi değil).

Yani bu senaryo bağlantı hatasına yol açacaktır :

Kaynak 1:

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

Kaynak 2:

extern const int global; //declaration

Bunun gibi olması gerekir:

Kaynak 1:

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

Kaynak 2:

extern const int global; //declaration

2
Tanım bölümünde 'extern' içermeden c ++ ile çalışırken neden yanlış?
Şef Shifter

1
Visual Micro ile VIsual Studio'da bu bağlantı hatasıyla karşılaşmıyorum. Neyi kaçırıyorum?
Craig.Feied

1
@ lartist93 @ Craig.Feied Tekrar dikkatlice kontrol etmeniz gerekebileceğine inanıyorum. Derleyici bağlantı hatasını bildirmese bile, her iki kaynaktan da her iki nesnenin de externtanımlanmadan aynı olup olmadığını kontrol edebilir misiniz ? Bunu globalkaynak 2'deki değeri yazdırarak yapabilirsiniz .
Trevor

3
Onayla, MSVS 2018 yılında orada olup olmadığını bir bağlantı hatası externiçinde atlanırsa const int global = 255;.
Evg

13

Bu, global bir değişkene sahip olmak istediğinizde kullanışlıdır. Bazı kaynak dosyadaki genel değişkenleri tanımlar ve bir başlık dosyasında extern olarak bildirirsiniz, böylece o başlık dosyasını içeren herhangi bir dosya aynı global değişkeni görür.


Her neyse, bu çok OOP gelmiyor, onları tek bir sınıfa
koyardım
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.