OC/C与C++混编找不到符号问题

Posted by LML on May 24, 2020

前言

在OC(C)与C++混合编程的时候,会遇到找不到符合的问题。本文从原理上进行详细分析

.mm、.cpp、.m(.c)文件区别

  • .mm 文件可以进行OC(C)与C++de混合编写,可以二者的哭都可以import,但是需要注意的上,非OC方法会按照C++的编译连接规范进行编译连接,产生相应的符号
  • .cpp 文件只可以编写C++代码,因此对于非类的方法会按照C++的编译连接规范进行编译连接,产生相应的符号
  • .m(.c)文件只能编译C代码,按照C的编译连接规范进行编译连接,产生相应的符号

C与C++编译连接产生的符号的区别

C++是一个面向对象语言(虽不是纯粹的面向对象语言),它支持函数的重载,重载这个特性给我们带来了很大的便利。为了支持函数重载的这个特性,C++编译器实际上将下面这些重载函数:

void print(int i); void print(char c); void print(float f); void print(char* s); 编译为:

_print_int _print_char _print_float _pirnt_string 这样的函数名,来唯一标识每个函数。注:不同的编译器实现可能不一样,但是都是利用这种机制。所以当连接是调用print(3)时,它会去查找_print_int(3)这样的函数。下面说个题外话,正是因为这点,重载被认为不是多态,多态是运行时动态绑定(“一种接口多种实现”),如果硬要认为重载是多态,它顶多是编译时“多态”。

C语言中并没有重载和类这些特性,故并不像C++那样print(int i),会被编译为_print_int,而是直接编译为_print等。

⚠️ 结论:C与C++产生的符号不相同,这是连接时候找不到符号的根本原因

函数产生(查找)C还是C++符号由什么决定

  • 实现函数的文件
    • C++(mm或者cpp) 的.h中正常声明(如下)或者.h不声明,产生C++符号
      void test();
      extern void test();
    
    • C++ (mm或者cpp)的.h中extern “C” 声明,产生C符号
      • 自己的.h 中不声明但是引用的.h里面声明extecn C 对应方法也会产生C符号
  • 调用函数的文件
    • 当是mm文件 调用其他方法
      • 若声明是普通声明,会按照C++符号查找
      • 若extern “C “ 会按照C符号查找
    • .m(.c)文件调用其他方法,默认按照C符号查找
  • 当查找的和产生的符号类型不一致,则会出错。
  • 还有一点需要注意
    • .h文件只是为了编译通过
    • link 能不能找到符号,需要看实现文件有没有对应符号。

混编的时候情况如何?

  • 如果OC(C)与C++混合编程,需要怎么办?
    • 使用 .mm 或cpp 文件
    • 但是这时候是按照C++的编译连接规则产生符号的
  • 如果OC(C)与C++混合编程,什么情况会出错?
    • C(C)要用到C++的方法,且没有进行额外处理(就是C++中被C调用的方法仍是普通声明)
    • 报错原因:C(C)中按照C符号规则找符号,但是C++产生的是C++规则符号。所以找不到符号
  • 如果OC(C)与C++混合编程,怎么保证肯定能找到符号?
    • 要么都用mm文件保证产生的符号和查找的符号都是C++规则
    • 如果OC(C)要用到C++的方法
      • 需要C++ 对被OC(C)调用的方法用 下面语句声明
      #ifdef __cplusplus
      extern "C" {
      #endif
    	 
      /*...*/
    	 
      #ifdef __cplusplus
      }
      #endif