Kapan menggunakan extern di C ++

399

Saya sedang membaca "Think in C ++" dan itu baru saja memperkenalkan externdeklarasi. Sebagai contoh:

extern int x;
extern float y;

Saya pikir saya mengerti artinya (deklarasi tanpa definisi), tapi saya bertanya-tanya kapan itu terbukti bermanfaat.

Adakah yang bisa memberikan contoh?

Aslan986
sumber
1
Saya harus memberikan definisi externpada beberapa kesempatan. Alat Microsoft menghasilkan kesalahan tautan untuk simbol yang hilang ketika tabel di file sumber lain hanya didefinisikan. Masalahnya adalah, tabelnya adalah constdan kompiler C ++ mempromosikannya ke staticdalam unit terjemahan. Lihat, misalnya, ariatab.cppdan kalynatab.cpp.
jww
2
Dan saya pikir jawaban Nik adalah yang benar karena dialah satu-satunya yang tampaknya telah menjawab pertanyaan C ++. Semua orang tampaknya telah menyimpang ke pertanyaan C.
jww

Jawaban:

520

Ini berguna ketika Anda memiliki variabel global. Anda mendeklarasikan keberadaan variabel global dalam header, sehingga setiap file sumber yang menyertakan header tahu tentang itu, tetapi Anda hanya perlu "mendefinisikan" sekali dalam salah satu file sumber Anda.

Untuk memperjelas, menggunakan extern int x;memberitahu kompiler bahwa objek jenis yang intdipanggil xada di suatu tempat . Ini bukan pekerjaan kompiler untuk mengetahui di mana ia ada, ia hanya perlu mengetahui jenis dan namanya sehingga ia tahu cara menggunakannya. Setelah semua file sumber dikompilasi, linker akan menyelesaikan semua referensix definisi yang ditemukan di salah satu file sumber yang dikompilasi. Agar dapat berfungsi, definisi xvariabel perlu memiliki apa yang disebut "hubungan eksternal", yang pada dasarnya berarti harus dinyatakan di luar fungsi (pada apa yang biasanya disebut "ruang lingkup file") dan tanpa statickata kunci.

tajuk:

#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

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

sumber 2:

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

void print_global_x()
{
    //print global_x here:
    std::cout << global_x << std::endl;
}
dreamlax
sumber
15
Terima kasih. Jadi, jika saya mendeklarasikan variabel global dalam file header tanpa kata kunci eksternal, file sumber yang menyertakan header tidak melihatnya?
Aslan986
23
Anda tidak boleh mendeklarasikan global vars dalam sebuah header, karena saat itu ketika 2 file menyertakan file header yang sama, itu tidak akan ditautkan (linker akan memancarkan kesalahan tentang "duplikat simbol")
kuba
63
@ Aslan986: Tidak, sesuatu yang lebih buruk terjadi. Setiap file sumber yang menyertakan header akan memiliki variabel sendiri , sehingga setiap file sumber akan dikompilasi secara independen tetapi linker akan mengeluh karena dua file sumber akan memiliki pengidentifikasi global yang sama.
dreamlax
7
Ketika Anda tidak menggunakan kata "extern", maka sekarang variabel ada. Ketika Anda menggunakan "extern", itu adalah "hei ada var ini di tempat lain". Maaf karena tidak menjawab apakah itu definisi atau deklarasi, karena saya selalu bingung tentang keduanya.
kuba
3
@ CCJ: penjaga sertakan hanya berfungsi untuk file sumber yang termasuk itu. Itu menghentikan header yang sama yang dimasukkan dua kali dalam file sumber yang sama (kalau-kalau header lain juga termasuk itu dll). Begitu pun dengan menyertakan penjaga, setiap file sumber yang menyertakan header masih akan memiliki definisi sendiri.
dreamlax
172

Ini berguna ketika Anda membagikan variabel di antara beberapa modul. Anda mendefinisikannya dalam satu modul, dan menggunakan eksternal dalam yang lain.

Sebagai contoh:

di file1.cpp:

int global_int = 1;

di file2.cpp:

extern int global_int;
//in some function
cout << "global_int = " << global_int;
MByD
sumber
39
Jawaban ini lebih benar daripada yang diterima, karena tidak menggunakan file header dan menyatakan dengan jelas bahwa itu hanya berguna ketika berbagi antara beberapa modul. Untuk aplikasi yang lebih besar lebih baik digunakan misalnya kelas ConfigManager.
Zac
1
Apakah ada gotcha ketika ruang nama terlibat, global_intada di ruang nama global, jika saya menggunakannya di file2.cpp di beberapa bagian ruang nama saya harus ruang lingkup yang benar? yaitunamespace XYZ{ void foo(){ ::global_int++ } };
jxramos
8
@Zac: Di sisi lain, dengan tidak mendeklarasikan variabel global dalam sebuah header, Anda secara tidak sengaja membuatnya jauh lebih sulit untuk menentukan di mana sebenarnya didefinisikan. Biasanya jika Anda melihat variabel global dideklarasikan abc.h, ada kemungkinan ia akan didefinisikan abc.cpp. IDE yang baik akan selalu membantu, tetapi kode yang terorganisir dengan baik selalu merupakan solusi yang lebih baik.
dreamlax
tanpa externdi file2.cpp, masih dapat mengakses global_intsetelah menyertakan. mengapa saya harus memilikinya?
TomSawyer
62

Ini semua tentang hubungan .

Jawaban sebelumnya memberikan penjelasan yang bagus tentang extern .

Tapi saya ingin menambahkan poin penting.

Anda bertanya tentang externdi C ++ tidak di C dan saya tidak tahu mengapa tidak ada jawaban yang menyebutkan tentang kasus ini ketika externdatang denganconst di C ++.

Dalam C ++, suatu constvariabel memiliki tautan internal secara default (tidak seperti C).

Jadi skenario ini akan menyebabkan kesalahan penautan :

Sumber 1:

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

Sumber 2:

extern const int global; //declaration

Itu harus seperti ini:

Sumber 1:

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

Sumber 2:

extern const int global; //declaration
Trevor
sumber
2
Mengapa ini salah ketika ia bekerja di c ++ tanpa menyertakan 'extern' di bagian definisi?
Kepala Shifter
1
Saya sepertinya tidak menemukan kesalahan penautan di Visual Studio dengan Visual Micro. Apa yang saya lewatkan?
Craig. Diisi
1
@ lartist93 @ Craig. Saya pikir Anda perlu memeriksa kembali dengan hati-hati. Bahkan jika kompiler tidak menginformasikan kesalahan penautan, dapatkah Anda memeriksa bahwa kedua objek di kedua sumber sama tanpa externdalam definisi? Anda dapat melakukannya dengan mencetak nilai globaldalam sumber 2.
Trevor
3
Konfirmasi, di MSVS 2018 ada adalah kesalahan yang menghubungkan jika externdihilangkan dalam const int global = 255;.
Evg
13

Ini berguna ketika Anda ingin memiliki variabel global. Anda mendefinisikan variabel global dalam beberapa file sumber, dan mendeklarasikannya di luar dalam file header sehingga setiap file yang menyertakan file header itu kemudian akan melihat variabel global yang sama.

Marlon
sumber
Bagaimanapun ini kedengarannya tidak terlalu OOP, saya akan menempatkan mereka ke dalam kelas singleton ... atau fungsi yang mengembalikan nilai statis lokal ...
RzR