คอมไพเลอร์ c ++ จะหาตัวแปรภายนอกได้อย่างไร


15

ฉันรวบรวมโปรแกรมนี้โดย g ++ และ clang ++ มีความแตกต่าง:
g ++ พิมพ์ 1 แต่พิมพ์ clang ++ 2
ดูเหมือนว่า
g ++: var var ที่กำหนดไว้ในขอบเขตที่สั้นที่สุด
clang ++: ตัวแปร extern ถูกกำหนดในขอบเขตโกลบอลที่สั้นที่สุด

ข้อมูลจำเพาะ C ++ มีข้อกำหนดใด ๆ

main.cpp

#include <iostream>
static int i;
static int *p = &i;

int main() {
  int i;
  {
    extern int i;
    i = 1;
    *p = 2;
    std::cout << i << std::endl;
  }
}

other.cpp

int i;

รุ่น: g ++: 7.4.0 / clang ++: การ
รวบรวม10.0.0 : $ (CXX) main.cpp other.cpp -o extern.exe


4
คอมไพเลอร์ไม่ได้ทำอะไรกับ extern ยกเว้นทำเครื่องหมายว่าเป็นตัวแปรที่มีการอ้างอิงภายนอกตัวเชื่อมโยงคือสิ่งที่พยายามแก้ไขลิงก์ระหว่างไฟล์วัตถุที่รวบรวมทั้งหมด
SPLatten

คำถามยอดเยี่ยม (ถ้าแปลก)! เล่นกับรหัสของคุณในMSVCและclang-cl(ให้ทั้งสอง2) ดูเหมือนว่าextern int iทั้งสองจะถูกละเว้นโดยสมบูรณ์: แม้ว่าฉันจะไม่เชื่อมโยงในother.cppไฟล์โปรแกรมสร้างและทำงาน
Adrian Mole

1
@SPlatten น่าจะเป็นเพราะ linker ไม่จำเป็นต้อง 'แก้ไข' การอ้างอิงถึงiมันไม่ได้ลอง
Adrian Mole

3
ข้อผิดพลาด GCC แบบเก่าที่เกี่ยวข้องที่ถูกระงับสามารถพบได้ที่นี่และข้อผิดพลาดแบบเปิดเสียงดังกราวที่นี่
walnut

คำตอบ:


11

[basic.link/7]ควรเป็นส่วนที่เกี่ยวข้องของมาตรฐาน ในร่างปัจจุบันจะกล่าวว่า:

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

โปรดทราบว่าตัวอย่างที่ตามมาเกือบจะตรงกับกรณีของคุณ:

static void f();
extern "C" void h();
static int i = 0;               // #1
void g() {
  extern void f();              // internal linkage
  extern void h();              // C language linkage
  int i;                        // #2: i has no linkage
  {
    extern void f();            // internal linkage
    extern int i;               // #3: external linkage, ill-formed
  }
}

ดังนั้นโปรแกรมควรมีรูปแบบไม่ดี คำอธิบายอยู่ด้านล่างตัวอย่าง:

หากไม่มีการประกาศที่บรรทัดที่ 2 การประกาศที่บรรทัดที่ 3 จะเชื่อมโยงกับการประกาศที่บรรทัดที่ 1 เนื่องจากการประกาศที่มีการเชื่อมโยงภายในถูกซ่อนอยู่ดังนั้น # 3 จึงได้รับการเชื่อมโยงภายนอกทำให้โปรแกรมไม่สามารถทำงานได้


โปรแกรมในตัวอย่างนั้นมีรูปแบบไม่ดีเนื่องจากไม่มี i ที่มีการเชื่อมโยงภายนอกที่กำหนดไว้ทุกที่ นี่ไม่ใช่กรณีที่มีตัวอย่างของ OP
n คำสรรพนาม 'm

3
@ n.'pronouns'm แต่กฎนี้ใช้กับหน่วยการแปล: หากภายในหน่วยการแปลหน่วยงานเดียวกันจะถูกประกาศด้วยการเชื่อมโยงทั้งภายในและภายนอกโปรแกรมจะเกิดรูปแบบไม่ถูกต้อง .
Daniel Langr

2
คำตอบเดียวที่นำไปใช้กับ C ++ 17 และต่อมาให้ดูที่ความละเอียดของCWG ปัญหา 426 สำหรับฉันดูเหมือนว่า GCC จะถูกต้องก่อนการเปลี่ยนแปลงนั้น
วอลนัท

ดูเหมือนว่าฉันกำลังอ่านมาตรฐานฉบับก่อนหน้า
n คำสรรพนาม 'm
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.