Namespaces
Variants

Language linkage

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

서로 다른 프로그래밍 언어로 작성된 프로그램 단위 간의 연결을 제공합니다.

이는 선언을 해당 모듈에서 분리하는 데에도 사용할 수 있습니다. 자세한 내용은 Module ownership 을 참조하십시오.

(since C++20)
extern string-literal { declaration-seq  (선택적) } (1)
extern string-literal declaration (2)
1) declaration-seq 내에서 선언된 모든 함수 타입, 외부 링크를 갖는 함수 이름, 그리고 외부 링크를 갖는 변수에 언어 사양 string-literal 을 적용합니다.
2) 언어 명세 string-literal 을 단일 선언 또는 정의에 적용합니다.
string-literal - 필요한 언어 연결을 지정하는 평가되지 않는 문자열 리터럴
declaration-seq - 중첩된 연결 지정을 포함할 수 있는 선언 시퀀스
declaration - 선언

목차

설명

모든 함수 타입, 모든 외부 링크 를 가진 함수 이름, 그리고 모든 외부 링크 를 가진 변수 이름은 언어 링크 라는 속성을 가집니다. 언어 링크는 다른 프로그래밍 언어로 작성된 프로그램 단위와 링크하기 위해 필요한 요구 사항들의 집합을 캡슐화합니다: 호출 규약 , 이름 맹글링 (이름 데코레이션) 알고리즘 등.

오직 두 가지 언어 연결만 지원이 보장됩니다:

  1. "C++" , 기본 언어 연결.
  2. "C" , C 프로그래밍 언어로 작성된 함수와 연결할 수 있게 하며, C++ 프로그램에서 C로 작성된 유닛에서 호출될 수 있는 함수를 정의할 수 있게 합니다.
extern "C"
{
    int open(const char *path_name, int flags); // C 함수 선언
}
int main()
{
    int fd = open("test.txt", 0); // C++ 프로그램에서 C 함수 호출
}
// 이 C++ 함수는 C 코드에서 호출될 수 있음
extern "C" void handler(int)
{
    std::cout << "Callback invoked\n"; // C++ 기능 사용 가능
}

언어 연결은 모든 함수 타입의 일부이므로, 함수 포인터도 언어 연결을 유지합니다. 함수 타입의 언어 연결(호출 규약을 나타냄)과 함수 이름의 언어 연결(네임 맹글링을 나타냄)은 서로 독립적입니다:

extern "C" void f1(void(*pf)()); // C 링크를 가지는 함수 f1을 선언합니다.
                             // 이 함수는 void를 반환하고, 매개변수를 취하지 않고 void를 반환하는
                             // C 함수에 대한 포인터를 인자로 받습니다
extern "C" typedef void FUNC(); // 매개변수를 취하지 않고 void를 반환하는 C 함수 타입으로
                                // FUNC를 선언합니다
FUNC f2;            // 이름 f2는 C++ 링크를 가지지만, 그 타입은 C 함수입니다
extern "C" FUNC f3; // 이름 f3는 C 링크를 가지며 그 타입은 C 함수 void()입니다
void (*pf2)(FUNC*); // 이름 pf2는 C++ 링크를 가지며, 그 타입은
                    // "void를 반환하고 '매개변수를 취하지 않고 void를 반환하는 C 함수에 대한
                    // 포인터' 타입의 인자를 하나 취하는 C++ 함수에 대한 포인터"입니다
extern "C"
{
    static void f4(); // 함수 f4의 이름은 내부 링크를 가집니다 (언어 링크 없음)
                      // 하지만 함수의 타입은 C 언어 링크를 가집니다
}

만약 동일한 엔티티의 두 선언 이 서로 다른 언어 링크를 부여한다면, 프로그램은 ill-formed입니다; 두 선언 중 어느 것도 다른 선언에서 도달할 수 없는 경우 진단은 요구되지 않습니다. 링크 지정 없이 엔티티를 재선언하는 경우 해당 엔티티와 그 타입(존재하는 경우)의 언어 링크를 상속받습니다.

extern "C" int f();
extern "C++" int f(); // 오류: 다른 언어 링크
extern "C" int g();
int g(); // OK, C 언어 링크를 가짐
int h(); // 기본적으로 C++ 언어 링크를 가짐
extern "C" int h(); // 오류: 다른 언어 링크

"C" 링크에 대한 특별 규칙

클래스 멤버 , 후행 requires 절을 가진 friend 함수 , (C++20부터) 또는 비정적 멤버 함수가 "C" 언어 블록에 나타날 때, 해당 타입들의 링크지는 "C++" 로 유지됩니다(하지만 매개변수 타입이 있는 경우 해당 타입은 "C" 로 유지됨):

extern "C"
{
    class X
    {
        void mf();           // 함수 mf와 그 타입은 C++ 언어 링크를 가짐
        void mf2(void(*)()); // 함수 mf2는 C++ 언어 링크를 가짐;
                             // 매개변수는 "C 함수에 대한 포인터" 타입을 가짐
    };
}
template<typename T>
struct A { struct B; };
extern "C"
{
    template<typename T>
    struct A<T>::B
    {
        friend void f(B*) requires true {} // C 언어 링크는 무시됨
    };
}
namespace Q
{
    extern "C" void f(); // 잘못된 형식이 아님
}

C "C" 언어 링크age를 가진 함수나 변수를 선언하는 선언이라고 가정합니다. 다른 선언 D 가 동일한 이름을 가진 엔티티를 선언하고 다음 조건 중 하나를 충족하는 경우, C D 는 동일한 엔티티를 선언합니다:

  • D 는 전역 범위에 속하는 변수를 선언합니다.
  • 만약 C 가 변수를 선언하면, D 도 변수를 선언합니다.
  • 만약 C 가 함수를 선언하면, D 도 함수를 선언합니다.

일반적인 재선언 과 달리, C D 는 서로 다른 대상 범위 를 가질 수 있습니다:

extern "C"
{
    int x;
    int f();
    int g() { return 1; }
}
namespace A
{
    int x;                // 오류: "x" 재정의
    int f();              // OK, "f" 재선언
    int g() { return 1; } // 오류: "g" 재정의
}

그러나 이러한 선언의 제한 사항 은 여전히 적용되며, 이는 둘 다 함수를 선언하거나 둘 다 변수를 선언해야 하며, 선언된 엔티티들은 동일한 타입을 가져야 함을 의미합니다:

namespace A
{
    extern "C" int x();
    extern "C" int y();
}
int x; // 오류: "x"를 다른 종류의 엔티티로 재선언함
namespace B
{
    void y(); // 오류: 다른 타입으로 "y"를 재선언함
}

참고 사항

언어 명세는 오직 namespace scope 에서만 나타날 수 있습니다.

언어 명세의 중괄호는 스코프를 생성하지 않습니다.

언어 사양이 중첩될 경우, 가장 안쪽의 사양이 유효하게 적용됩니다.

언어 연결 명세 내에 직접 포함된 선언은 선언된 이름의 extern 지정자 를 포함하는 것처럼 처리되며, 이를 통해 링크 여부와 정의 인지의 여부가 결정됩니다.

extern "C" int x; // 선언이지 정의가 아님
// 위 줄은 extern "C" { extern int x; }와 동등함
extern "C" { int x; } // 선언이면서 정의
extern "C" double f();
static double f(); // 오류: 링크age 충돌
extern "C" static void g(); // 오류: 링크age 충돌

extern "C" 는 C++ 프로그램에서 C 라이브러리 함수 선언을 포함하는 헤더 파일을 포함할 수 있게 해주지만, 동일한 헤더 파일이 C 프로그램과 공유되는 경우 extern "C" (C에서는 허용되지 않음)는 적절한 #ifdef , 일반적으로 __cplusplus 로 숨겨져야 합니다:

#ifdef __cplusplus
extern "C" int foo(int, int); // C++ 컴파일러가 이 코드를 봄
#else
int foo(int, int);            // C 컴파일러가 이 코드를 봄
#endif

"C"와 "C++" 언어 링크로 함수 타입을 구분하는 유일한 현대 컴파일러는 Oracle Studio이며, 다른 컴파일러들은 언어 링크만 다른 오버로드를 허용하지 않습니다. 이는 C++ 표준에서 요구하는 오버로드 집합( std::qsort , std::bsearch , std::signal , std::atexit , 그리고 std::at_quick_exit )을 포함합니다: GCC 버그 2316 , Clang 버그 6277 , CWG 이슈 1555 .

extern "C"   using c_predfun   = int(const void*, const void*);
extern "C++" using cpp_predfun = int(const void*, const void*);
// 형식적으로 잘못되었으나, 대부분의 컴파일러에서 허용됨
static_assert(std::is_same<c_predfun, cpp_predfun>::value,
              "C와 C++ 언어 링크는 함수 타입을 구분하지 않아야 합니다.");
// 다음 선언들은 대부분의 컴파일러에서 오버로드로 선언되지 않음
// c_predfun과 cpp_predfun이 동일한 타입으로 간주되기 때문
void qsort(void* base, std::size_t nmemb, std::size_t size, c_predfun*   compar);
void qsort(void* base, std::size_t nmemb, std::size_t size, cpp_predfun* compar);

키워드

extern

결함 보고서

다음의 동작 변경 결함 보고서들은 이전에 발표된 C++ 표준에 소급 적용되었습니다.

DR 적용 대상 게시된 동작 올바른 동작
CWG 4 C++98 내부 링크age를 가진 이름이 언어 링크age를 가질 수 있음 외부 링크age를 가진 이름으로 제한됨
CWG 341 C++98 "C" 언어 링크age를 가진 함수가
전역 변수와 같은 이름을 가질 수 있음
이 경우 프로그램이 잘못된 형태임
(서로 다른 번역 단위에 나타나는 경우
진단 메시지 불필요)
CWG 564 C++98 두 선언이 언어 링크age 명세에서만 다른 경우
(즉, 'extern' 뒤에 오는 문자열 리터럴이 다른 경우)
프로그램이 잘못된 형태였음
대신 선언에서 주어진 실제 언어 링크age를
비교함
CWG 2460 C++20 후행 requires 절을 가진 friend 함수와
"C" 언어 링크age가 충돌하는 동작을 가짐
이 경우 "C" 언어 링크age는
무시됨
CWG 2483 C++98 "C" 언어 블록에 나타나는 정적 멤버 함수의
타입 링크age가 "C++" 였음
링크age는 "C"

참조문헌

  • C++23 표준 (ISO/IEC 14882:2024):
  • 9.11 링크 규격 [dcl.link]
  • C++20 표준 (ISO/IEC 14882:2020):
  • 9.11 링크 규격 [dcl.link]
  • C++17 표준 (ISO/IEC 14882:2017):
  • 10.5 링크 규격 [dcl.link]
  • C++14 표준(ISO/IEC 14882:2014):
  • 7.5 링크 규격 [dcl.link]
  • C++11 표준 (ISO/IEC 14882:2011):
  • 7.5 링크 규격 [dcl.link]
  • C++03 표준(ISO/IEC 14882:2003):
  • 7.5 링크 규격 [dcl.link]
  • C++98 표준(ISO/IEC 14882:1998):
  • 7.5 링크 규격 [dcl.link]