เมื่อใดที่จะใช้ extern ใน C ++


398

ฉันกำลังอ่าน "คิดใน C ++" และมันเพิ่งเปิดตัวการexternประกาศ ตัวอย่างเช่น:

extern int x;
extern float y;

ฉันคิดว่าฉันเข้าใจความหมาย (ประกาศโดยไม่มีคำจำกัดความ) แต่ฉันสงสัยว่ามันจะมีประโยชน์เมื่อใด

บางคนสามารถให้ตัวอย่างได้หรือไม่?


1
ฉันต้องให้คำจำกัดความด้วยexternหลายครั้ง เครื่องมือของ Microsoft สร้างข้อผิดพลาดในการเชื่อมโยงสำหรับสัญลักษณ์ที่หายไปเมื่อกำหนดตารางในไฟล์ต้นฉบับอื่นแล้วเท่านั้น ปัญหาคือตารางconstและคอมไพเลอร์ C ++ เลื่อนไปที่staticในหน่วยการแปล ดูตัวอย่างเช่น, และariatab.cpp kalynatab.cpp
jww

2
และฉันคิดว่าคำตอบของ Nik เป็นคำตอบที่ถูกต้องเพราะเขาเป็นคนเดียวที่ตอบคำถาม C ++ ดูเหมือนคนอื่น ๆ จะพูดกับคำถามซี
jww

คำตอบ:


519

สิ่งนี้มีประโยชน์เมื่อคุณมีตัวแปรส่วนกลาง คุณประกาศการมีอยู่ของตัวแปรโกลบอลในส่วนหัวเพื่อให้ไฟล์ต้นฉบับแต่ละไฟล์ที่มีส่วนหัวรู้เกี่ยวกับมัน แต่คุณจะต้อง "กำหนด" มันหนึ่งครั้งในหนึ่งในไฟล์ต้นฉบับของคุณ

ชี้แจงโดยใช้extern int x;บอกคอมไพเลอร์ที่ว่าวัตถุของการพิมพ์ที่intเรียกว่าxอยู่ที่ไหนสักแห่ง มันไม่ใช่งานของคอมไพเลอร์ที่จะรู้ว่ามันอยู่ที่ไหนมันแค่ต้องรู้ประเภทและชื่อเพื่อที่จะรู้วิธีใช้มัน เมื่อรวบรวมไฟล์ต้นฉบับทั้งหมดแล้วตัวเชื่อมโยงจะแก้ไขการอ้างอิงทั้งหมดของxคำจำกัดความเดียวที่พบในไฟล์ต้นฉบับที่รวบรวม เพื่อให้ทำงานได้คำจำกัดความของxตัวแปรจำเป็นต้องมีสิ่งที่เรียกว่า "การเชื่อมโยงภายนอก" ซึ่งโดยทั่วไปหมายความว่ามันจะต้องประกาศนอกฟังก์ชั่น (ที่มักเรียกว่า "ขอบเขตไฟล์") และไม่มีstaticคำหลัก

หัวข้อ:

#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

ที่มา 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();
}

ที่มา 2:

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

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

15
ขอบคุณ. ดังนั้นถ้าฉันประกาศตัวแปรทั่วโลกในไฟล์ส่วนหัวโดยไม่มีคำหลัก extern ไฟล์ต้นฉบับที่มีส่วนหัวไม่เห็นหรือไม่
Aslan986

23
คุณไม่ควรประกาศ vars ระดับโลกในส่วนหัวแล้วเพราะเมื่อ 2 ไฟล์รวมถึงไฟล์ส่วนหัวเดียวกันก็จะไม่เชื่อมโยง (ลิงเกอร์จะปล่อยข้อผิดพลาดเกี่ยวกับ "สัญลักษณ์ที่ซ้ำกัน")
kuba

63
@ Aslan986: ไม่เกิดอะไรขึ้นที่เลวร้ายยิ่งขึ้น ไฟล์ต้นฉบับแต่ละไฟล์ที่มีส่วนหัวจะมีตัวแปรของตัวเองดังนั้นไฟล์ต้นฉบับแต่ละไฟล์จะรวบรวมอย่างอิสระ แต่ตัวเชื่อมโยงจะบ่นเพราะไฟล์ต้นฉบับสองไฟล์จะมีตัวระบุสากลเดียวกัน
dreamlax

7
เมื่อคุณไม่ได้ใช้คำว่า "extern" ดังนั้นตอนนี้ตัวแปรจึงมีอยู่ เมื่อคุณใช้ "extern" มันเป็น "เฮ้มี var นี้อยู่ที่อื่น" ขออภัยที่ไม่ตอบว่าเป็นคำจำกัดความหรือคำประกาศเนื่องจากฉันสับสนเกี่ยวกับสิ่งเหล่านี้เสมอ
kuba

3
@CCJ: การป้องกันรวมใช้งานได้กับไฟล์ต้นฉบับที่รวมไว้เท่านั้น มันหยุดส่วนหัวเดียวกันถูกรวมสองครั้งในไฟล์ต้นฉบับเดียวกัน (ในกรณีที่ส่วนหัวอื่น ๆ รวมถึงมัน ฯลฯ ) ดังนั้นแม้จะมียามรักษาความปลอดภัยไฟล์ต้นฉบับแต่ละไฟล์ที่มีส่วนหัวจะยังคงมีคำจำกัดความของตัวเอง
dreamlax

172

มันจะมีประโยชน์เมื่อคุณแชร์ตัวแปรระหว่างโมดูลสองสามตัว คุณกำหนดไว้ในโมดูลหนึ่งและใช้ภายนอกในโมดูลอื่น

ตัวอย่างเช่น:

ใน file1.cpp:

int global_int = 1;

ใน file2.cpp:

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

39
คำตอบนี้ถูกต้องมากกว่าคำตอบที่ยอมรับเนื่องจากไม่ได้ใช้ประโยชน์จากไฟล์ส่วนหัวและระบุอย่างชัดเจนว่ามีประโยชน์เฉพาะเมื่อใช้ร่วมกันระหว่างโมดูลน้อย สำหรับแอปพลิเคชันขนาดใหญ่จะดีกว่าที่จะใช้ตัวอย่างเช่นคลาส ConfigManager
Zac

1
มี gotchas ใด ๆ เมื่อ namespaces เกี่ยวข้อง, global_intอยู่ใน namespace ทั่วโลก, ถ้าฉันจะใช้มันใน file2.cpp ในบางส่วนของ namespace ฉันจะต้องกำหนดขอบเขตให้ถูกต้องหรือไม่? ienamespace XYZ{ void foo(){ ::global_int++ } };
jxramos

8
@Zac: ในทางกลับกันหากไม่ประกาศตัวแปรโกลบอลในส่วนหัวคุณได้ตั้งใจทำให้ยากขึ้นในการพิจารณาว่ามันถูกกำหนดไว้ที่ไหน โดยปกติถ้าคุณเห็นตัวแปรทั่วโลกประกาศในมีโอกาสที่ดีที่จะถูกกำหนดไว้ในabc.h abc.cppIDE ที่ดีจะช่วยได้ตลอดเวลา แต่รหัสที่มีการจัดระเบียบอย่างดีจะเป็นทางออกที่ดีกว่าเสมอ
Dreamlax

โดยไม่มีexternใน file2.cpp ยังคงสามารถเข้าถึงglobal_intหลังจากรวม ทำไมฉันต้องมีมัน
TomSawyer

62

มันคือทั้งหมดที่เกี่ยวกับการเชื่อมโยง

คำตอบก่อนหน้านี้มีให้ explainations externที่ดีเกี่ยวกับ

แต่ฉันต้องการเพิ่มจุดสำคัญ

คุณถามเกี่ยวกับexternในC ++ไม่ใช่ในCและฉันไม่รู้ว่าทำไมไม่มีคำตอบที่กล่าวถึงกรณีและปัญหาเมื่อexternมาconstใน C ++

ใน C ++ constตัวแปรจะมีการเชื่อมโยงภายในโดยค่าเริ่มต้น (ไม่เหมือน C)

ดังนั้นสถานการณ์นี้จะนำไปสู่ข้อผิดพลาดในการเชื่อมโยง :

ที่มา 1:

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

ที่มา 2:

extern const int global; //declaration

ต้องเป็นเช่นนี้:

ที่มา 1:

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

ที่มา 2:

extern const int global; //declaration

2
เหตุใดจึงผิดในขณะที่ทำงานใน c ++ โดยไม่รวม 'extern' ในส่วนคำจำกัดความ
หัวหน้าชิฟเตอร์

1
ฉันไม่พบข้อผิดพลาดในการเชื่อมโยงใน VIsual Studio กับ Visual Micro ฉันพลาดอะไรไป
Craig.Feied

1
@ lartist93 @ Craig.Feied ฉันเชื่อว่าคุณอาจต้องตรวจสอบอีกครั้งอย่างระมัดระวัง แม้ในกรณีที่คอมไพเลอร์ไม่แจ้งข้อผิดพลาดในการเชื่อมโยงคุณสามารถตรวจสอบว่าวัตถุทั้งสองในแหล่งที่มานั้นเหมือนกันโดยไม่มีexternคำจำกัดความหรือไม่? คุณสามารถทำได้โดยพิมพ์ค่าของglobalแหล่ง 2
เทรเวอร์

3
ยืนยันใน MSVS 2018 มีเป็นข้อผิดพลาดการเชื่อมโยงถ้าถูกละไว้ในextern const int global = 255;
Evg

13

สิ่งนี้มีประโยชน์เมื่อคุณต้องการมีตัวแปรโกลบอล คุณกำหนดตัวแปรโกลบอลในไฟล์ต้นฉบับบางไฟล์และประกาศภายนอกในไฟล์ส่วนหัวเพื่อให้ไฟล์ใด ๆ ที่มีไฟล์ส่วนหัวนั้นจะเห็นตัวแปรโกลบอลเดียวกัน


อย่างไรก็ตามนี้ไม่ได้เสียงมาก OOP ผมจะวางไว้ในระดับเดี่ยว ... หรือฟังก์ชั่นที่กลับมาเป็นค่าคงที่ในท้องถิ่น ...
RZR
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.