Biên dịch một g++nhị phân được tạo để xem những gì đang xảy ra
Để hiểu tại sao externcần thiết, điều tốt nhất cần làm là hiểu chi tiết những gì đang diễn ra trong các tệp đối tượng với một ví dụ:
main.cpp
void f() {}
void g();
extern "C" {
    void ef() {}
    void eg();
}
/* Prevent g and eg from being optimized away. */
void h() { g(); eg(); }
Biên dịch với đầu ra ELF GCC 4.8 Linux :
g++ -c main.cpp
Dịch ngược bảng ký hiệu:
readelf -s main.o
Đầu ra chứa:
Num:    Value          Size Type    Bind   Vis      Ndx Name
  8: 0000000000000000     6 FUNC    GLOBAL DEFAULT    1 _Z1fv
  9: 0000000000000006     6 FUNC    GLOBAL DEFAULT    1 ef
 10: 000000000000000c    16 FUNC    GLOBAL DEFAULT    1 _Z1hv
 11: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _Z1gv
 12: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND eg
Diễn dịch
Chúng ta thấy rằng:
- efvà- egđược lưu trữ trong các ký hiệu có cùng tên như trong mã
 
- các biểu tượng khác được đọc sai Chúng ta hãy tháo gỡ chúng: - $ c++filt _Z1fv
f()
$ c++filt _Z1hv
h()
$ c++filt _Z1gv
g()
 
Kết luận: cả hai loại ký hiệu sau không được đọc sai:
- xác định
- khai báo nhưng không xác định ( Ndx = UND), được cung cấp tại liên kết hoặc thời gian chạy từ tệp đối tượng khác
Vì vậy, bạn sẽ cần extern "C"cả hai khi gọi:
- C từ C ++: nói g++để mong đợi các biểu tượng không bị thay đổi được tạo bởigcc
- C ++ từ C: yêu g++cầu tạo các ký hiệu không thay đổigccđể sử dụng
Những thứ không hoạt động ở bên ngoài C
Rõ ràng là bất kỳ tính năng C ++ nào yêu cầu xáo trộn tên sẽ không hoạt động bên trong extern C:
extern "C" {
    // Overloading.
    // error: declaration of C function ‘void f(int)’ conflicts with
    void f();
    void f(int i);
    // Templates.
    // error: template with C linkage
    template <class C> void f(C i) { }
}
C runnable tối thiểu từ ví dụ C ++
Để hoàn thiện và cho các newbs ngoài kia, hãy xem thêm: Làm thế nào để sử dụng các tệp nguồn C trong một dự án C ++?
Gọi C từ C ++ khá dễ dàng: mỗi hàm C chỉ có một biểu tượng không bị sai lệch, do đó không cần phải làm thêm.
main.cpp
#include <cassert>
#include "c.h"
int main() {
    assert(f() == 1);
}
ch
#ifndef C_H
#define C_H
/* This ifdef allows the header to be used from both C and C++. */
#ifdef __cplusplus
extern "C" {
#endif
int f();
#ifdef __cplusplus
}
#endif
#endif
cc
#include "c.h"
int f(void) { return 1; }
Chạy:
g++ -c -o main.o -std=c++98 main.cpp
gcc -c -o c.o -std=c89 c.c
g++ -o main.out main.o c.o
./main.out
Không có extern "C"liên kết thất bại với:
main.cpp:6: undefined reference to `f()'
bởi vì g++hy vọng sẽ tìm thấy một máng xối f, mà gcckhông sản xuất.
Ví dụ trên GitHub .
C ++ tối thiểu có thể chạy được từ ví dụ C
Gọi C ++ từ khó hơn một chút: chúng ta phải tự tạo các phiên bản không bị xáo trộn của từng chức năng mà chúng ta muốn phơi bày.
Ở đây chúng tôi minh họa cách phơi bày quá tải chức năng C ++ cho C.
C chính
#include <assert.h>
#include "cpp.h"
int main(void) {
    assert(f_int(1) == 2);
    assert(f_float(1.0) == 3);
    return 0;
}
cpp.h
#ifndef CPP_H
#define CPP_H
#ifdef __cplusplus
// C cannot see these overloaded prototypes, or else it would get confused.
int f(int i);
int f(float i);
extern "C" {
#endif
int f_int(int i);
int f_float(float i);
#ifdef __cplusplus
}
#endif
#endif
cpp.cpp
#include "cpp.h"
int f(int i) {
    return i + 1;
}
int f(float i) {
    return i + 2;
}
int f_int(int i) {
    return f(i);
}
int f_float(float i) {
    return f(i);
}
Chạy:
gcc -c -o main.o -std=c89 -Wextra main.c
g++ -c -o cpp.o -std=c++98 cpp.cpp
g++ -o main.out main.o cpp.o
./main.out
Không có extern "C"nó thất bại với:
main.c:6: undefined reference to `f_int'
main.c:7: undefined reference to `f_float'
bởi vì g++tạo ra các biểu tượng mangled mà gcckhông thể tìm thấy.
Ví dụ trên GitHub .
Đã thử nghiệm trong Ubuntu 18.04.