链接指示:extern "C"

在C++程序中调用其他语言编写的函数,例如C语言。
要求有权访问该语言的编译器,并且该编译器与当前C++编译器兼容。

声明非C++函数

  • 两种形式:单语句、复合语句。
  • 链接指示不能出现在类定义或函数定义内部。
  • 非C++函数的每个声明中都必须具有相同的链接指示。
    1
    2
    3
    4
    5
    6
    7
    8
    // 单语句链接指示
    extern "C" size_t strlen(const char *);

    // 复合语句链接指示
    extern "C" {
    int strcmp(const char *, const char *);
    char *strcat(char *, const char *);
    }

链接指示与头文件

  • 采用复合声明的形式。

    1
    2
    3
    extern "C" {
    #include <string.h>
    }
  • 头文件中的所有普通函数声明都被认为是由链接指示的语言编写的。

  • 链接指示可以嵌套,如果头文件包含自带链接指示的函数,那么该函数的链接不受影响。

导出C++函数到其他语言

  • 通过使用链接指示对函数进行定义:
    1
    extern "C" double calc(double dparm) { /* ... */ }

指向 extern “C” 函数的指针

  • 编写函数所用的语言是函数类型的一部分。
    因此,对于使用链接指示定义的函数而言,它的每个声明中都必须具有相同的链接指示。并且,指向函数的指针必须与函数本身使用相同的链接指示。

    1
    2
    3
    void (*pf1) (int); // 指向一个C++函数
    extern "C" void (*pf2) (int); // 指向一个C函数
    pf1 = pf2; // 错误:pf1与pf2的类型不同
  • 链接指示不仅对函数有效,而且对作为返回类型或形参类型的函数指针也有效。

    1
    2
    3
    4
    5
    6
    // f是一个C函数,参数是一个指向C函数的指针
    // 调用f时,必须传入一个C函数的名字或者指向C函数的指针。
    extern "C" void f(void (*) (int));

    // 函数名代表某个函数的入口地址(常量)
    // 函数指针相当于变量,可以存放所有该类型函数的入口地址
  • 因为链接指示同时作用于声明语句中的所有函数(指针),
    所以如果要给C++函数传入一个指向C函数的指针,则必须使用类型别名。

    1
    2
    3
    4
    // FC为函数指针类型,指向一个C函数
    extern "C" typedef void (*FC)(int);
    // f2是一个C++函数,形参为一个指向C函数的指针
    void f2(FC);

链接指示与重载函数

  • 链接指示与重载函数的相互作用依赖于目标语言。
  • C语言不支持重载,故一个C链接指示只能用于说明一组重载函数中的一个。

    1
    2
    3
    // 错误:两个 extern "C" 函数名相同
    extern "C" void print(const char *);
    extern "C" void print(int);
  • 如果一组重载函数中有一个是C函数(可在C或C++中被调用),则其余的都必须为C++函数(只能在C++中被调用)