C ++ derleyicileri extern değişkenini nasıl bulur?


15

Bu programı g ++ ve clang ++ ile derledim. Bir fark var:
g ++ 1 yazdırır, ancak clang ++ 2 yazdırır.
Görünüşe göre
g ++: extern değişkeni en kısa kapsamda tanımlanmıştır.
clang ++: extern değişkeni en kısa global kapsamda tanımlanır.

C ++ spec bu konuda herhangi bir şartname var mı?

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;

sürüm: g ++: 7.4.0 / clang ++: 10.0.0
derleme: $ (CXX) main.cpp diğer.cpp -o extern.exe


4
Derleyici, harici referanslara sahip değişkenler olarak işaretlemek dışında extern ile hiçbir şey yapmaz, bağlayıcı, derlenmiş tüm nesne dosyaları arasındaki bağlantıları çözmeye çalışır.
Ocak'ta

Mükemmel (garip ise) bir soru! Kodunuzu MSVCve clang-cl(her ikisi de vermek 2) ile extern int iuğraşırken, her ikisi tarafından tamamen görmezden geliyor gibi görünüyor : ben other.cppdosyada bağlantı olmasa bile , program inşa ve çalışır.
Adrian Mole

1
@SPlatten Muhtemelen, bağlayıcının referansı 'çözmesi' gerekmediğinden, denemez i.
Adrian Mole

3
İlgili eski askıya alınmış GCC hatası burada ve ilgili açık Clang hatasını burada bulabilirsiniz
ceviz

Yanıtlar:


11

[basic.link/7] , Standardın ilgili bölümü olmalıdır. Mevcut taslakta şöyle diyor:

Blok kapsamı içinde bildirilen bir işlevin adı ve blok kapsamı externbildirimi ile bildirilen bir değişkenin adı bağlantılıdır. Adlandırılmış bir modüle böyle bir bildirim eklenirse, program yanlış biçimlendirilir. Bağlantılı bir işletmenin görünür bir beyanı varsa, en içteki isim alanı kapsamı dışında beyan edilen varlıkları göz ardı ederek, iki beyan aynı beyan bölgesinde ortaya çıkarsa, blok kapsam beyanı (muhtemelen kötü biçimlendirilmiş) bir yeniden beyan olacaktır, blok kapsamı beyanı aynı kuruluşu beyan eder ve önceki beyannamenin bağlantısını alır. Bu tür birden fazla eşleşen varlık varsa, program kötü biçimlendirilmiştir. Aksi takdirde, eşleşen varlık bulunmazsa, blok kapsamı varlığı harici bağlantı alır.Bir çeviri biriminde aynı kuruluş hem iç hem de dış bağlantı ile ilan edilirse, program kötü biçimlendirilir.

Sonraki örneğin neredeyse davanızla tam olarak eşleştiğini unutmayın:

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

Bu nedenle, program kötü biçimlendirilmelidir. Açıklama örneğin altındadır:

# 2 satırındaki bildirim olmadan, # 3 satırındaki bildirim 1 numaralı satırdaki bildirimle bağlantı kuracaktır. Bununla birlikte, iç bağlantı ile bildirimi gizlendiğinden, # 3'e dış bağlantı verilir ve bu da programı kötü biçimlendirir.


Dış bağlantı ile bir orada olduğu için örneğin program kötü oluşturulur tanımlanan herhangi bir yerde. OP örneği için durum böyle değil.
n. 'zamirler' m.

3
@ n.'pronouns'm. Ancak kural bir çeviri birimi için geçerlidir: Bir çeviri birimi içinde aynı kuruluş hem iç hem de dış bağlantı ile bildirilirse, program kötü biçimlendirilir. .
Daniel Langr

2
Cevap sadece C ++ 17 ve üstü için geçerlidir, bkz. CWG sorunu 426'nın çözümü . Bana öyle geliyor ki GCC bu değişiklikten önce doğruydu.
Ceviz

Tamam standartın önceki baskısını okuyordu gibi görünüyor.
n. 'zamirler' 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.