Làm thế nào để trình biên dịch c ++ tìm thấy một biến extern?


15

Tôi biên dịch chương trình này bằng g ++ và clang ++. Có một sự khác biệt:
g ++ in 1, nhưng clang ++ in 2.
Dường như
g ++: biến ngoài được xác định trong phạm vi ngắn nhất.
clang ++: biến ngoài được xác định trong phạm vi toàn cầu ngắn nhất.

Thông số kỹ thuật C ++ có bất kỳ đặc điểm kỹ thuật về điều đó?

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;

phiên bản: g ++: 7.4.0 / clang ++:
Biên dịch 10.0.0 : $ (CXX) main.cpp other.cpp -o extern.exe


4
Trình biên dịch không làm bất cứ điều gì với extern ngoại trừ đánh dấu chúng là các biến có tham chiếu bên ngoài, trình liên kết là thứ cố gắng giải quyết các liên kết giữa tất cả các tệp đối tượng được biên dịch.
SPlatten

Một câu hỏi xuất sắc (nếu lạ)! Chơi xung quanh với mã của bạn trong MSVCclang-cl(cả hai cho 2), dường như extern int icả hai đều bị bỏ qua hoàn toàn: ngay cả khi tôi không liên kết trong other.cpptệp, chương trình sẽ xây dựng và chạy.
Adrian Mole

1
@SPlatten Có lẽ, vì trình liên kết không cần 'giải quyết' tham chiếu đến i, nên nó không thử.
Adrian Mole

3
Có thể tìm thấy lỗi GCC bị treo cũ liên quan tại đây và lỗi Clang mở tương ứng tại đây
quả óc chó

Câu trả lời:


11

[basic.link/7] phải là phần có liên quan của Tiêu chuẩn. Trong dự thảo hiện tại, nó nói:

Tên của một hàm được khai báo trong phạm vi khối và tên của một biến được khai báo bởi một externkhai báo phạm vi khối có liên kết. Nếu một tuyên bố như vậy được gắn vào một mô-đun có tên, chương trình không được định dạng. Nếu có một tuyên bố có thể nhìn thấy của một thực thể có liên kết, bỏ qua các thực thể được khai báo bên ngoài phạm vi không gian tên kèm theo trong cùng, thì khai báo phạm vi khối sẽ là một khai báo (có thể không được định dạng) nếu hai khai báo xuất hiện trong cùng một vùng khai báo, khai báo phạm vi khối khai báo cùng một thực thể và nhận được liên kết của khai báo trước đó. Nếu có nhiều hơn một thực thể phù hợp như vậy, chương trình sẽ không được định dạng. Mặt khác, nếu không tìm thấy thực thể phù hợp, thực thể phạm vi khối sẽ nhận được liên kết bên ngoài.Nếu, trong một đơn vị dịch thuật, cùng một thực thể được khai báo với cả liên kết bên trong và bên ngoài, chương trình không được định dạng.

Lưu ý rằng ví dụ tiếp theo gần như khớp chính xác với trường hợp của bạ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
  }
}

Vì vậy, chương trình nên được hình thành. Giải thích bên dưới ví dụ:

Nếu không có khai báo ở dòng số 2, khai báo ở dòng số 3 sẽ liên kết với khai báo ở dòng số 1. Tuy nhiên, vì khai báo với liên kết nội bộ bị ẩn, # 3 được cung cấp liên kết bên ngoài, làm cho chương trình không được định dạng.


Chương trình trong ví dụ này không được định dạng vì không có i với liên kết ngoài được xác định ở bất cứ đâu. Đây không phải là trường hợp với ví dụ của OP.
n. 'đại từ' m.

3
@ n.'pronouns'm. Nhưng quy tắc áp dụng cho một đơn vị dịch thuật: Nếu, trong một đơn vị dịch thuật, cùng một thực thể được khai báo với cả liên kết bên trong và bên ngoài, chương trình không được định dạng. .
Daniel Langr

2
Câu trả lời chỉ áp dụng cho C ++ 17 trở lên, xem giải quyết vấn đề CWG 426 . Dường như với tôi rằng GCC đã đúng trước sự thay đổi đó.
quả óc chó

OK có vẻ như tôi đã đọc phiên bản trước của tiêu chuẩn.
n. 'đại từ' m.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.