设为首页 加入收藏

TOP

C++编译链接的那些小事(三)
2014-02-08 13:37:11 来源: 作者: 【 】 浏览:324
Tags:编译 链接 那些 小事

 

  看到了吧,链接器ld报出了链接错误,原因是hello_world这个函数找不到。这个例子很简单,基本上可以区分出编译错误和链接错误。我们再添加一个hello_world.cpp

  void hello_world()

  {

  }

  编译

  coderchen@coderchen:~/c++$ g++ -c -o hello_world.o hello_world.cpp

  链接

  coderchen@coderchen:~/c++之所以$ g++ -o main main.o hello_world.o

  ok,我们的main程序已经生成了,我们经历了预处理---编译---链接的过程。

  有的人说为什么不需要写一个hello_world.h的头文件,声明hello_world函数,然后再让main.cpp包含hello_world.h呢?这样写自然是标准的做法,不过预处理过后,和我们现在写的一样的,预处理会把hello_world.h的内容替换到main.cpp中。

  问题:在链接的时候,main.o怎么知道hello_world函数定义在hello_world.o中呢?

  答案:main.o不知道hello_world函数定义在那个obj文件中,每个obj文件都有一个导出符号表,对于这个例子,hello_world.o的导出符号表中有hello_world这个函数,而main.o需要用到这个函数,可以想象就像几个插槽一样。链接器通过扫描obj文件发现这个函数定义在hello_world.o中,然后就可以链接了。

  问题:为什么函数不能定义在头文件中?

  这个问题是不恰当的,因为用inline和static修饰的函数可以定义在头文件中,而inline修饰的函数必须定义在头文件中。

  如果函数定义在头文件中,并且有多个cpp文件都包含了这个头文件的话,那么这些cpp文件生成的obj文件的导出符号表中都有这个头文件中定义的函数,单文件编译的时候是不会出错的,但是链接的时候就会报错。链接器发现了多个函数实体,但却无法确定应该使用哪一个。这是一个链接错误。

  inline修饰的函数,通常都不会存在函数实体,即便编译器没有对其内联,那么obj文件也不会导出inline函数,所以链接不会出错。

  static修饰的函数,只能由定义它的编译单元调用,也不会导出。如果头文件中顶一个static修饰的函数,就相当于多个obj文件中都顶一个了一个一模一样的函数,大家各用各的,互补干扰。

  问题:什么样的变量可以定义在头文件中?

  其实变量于函数很类似,由static或const修饰的变量可以定义在头文件中。

  static修饰的变量于static修饰的函数一样,道理同上。

  const修饰的变量默认是不会进入导出符号表的,相当于每个obj中都定义了一个一模一样的const变量,各用各的。而const可以再用extern修饰,如果用extern const修饰的变量定义在头文件中,那么就会出现链接错误,原因就是"想一想extern是干嘛的"

  问题:extern "C"是干嘛的?

  如果有人回答"兼容C和C++",我只能说"这是一个正确答案,但我不知道你是否真的知道".

  首先要知道C不支持重载,C++支持重载,C++为了支持重载,引入了函数重命名的机制,就像下面这样:

  int hello_world(type1 param);

  int hello_world(type2 param);

  通常第一个函数会被编译成hello_world_type1这样子,第二个函数会被编译成hello_world_type2这样子。不管是定义的地方还是调用的地方,都会把函数改成同样的名字,所以链接器可以正确的找到函数实体。

  而我们写C++程序的时候,通常会引入由c编写的库(gcc编译的c文件),而c不支持重载,自然不会对函数重命名。而我们在C++中调用的地方很可能会重命名,这就造成了调用的地方(C++编译)和定义的地方(C编译)函数名不一致的情况,这也是一种链接错误。

  所以我们经常会看到在C++中用extern "C" { #include "some_c.h" }这种代码。这就是告诉c++编译器,some_c.h中的函数要按照c的方式编译,不要重命名,这样在链接的时候就ok了。

      

首页 上一页 1 2 3 下一页 尾页 3/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇C++中的位运算符 下一篇C++和C#之间互相调用经验详谈

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

·Libevent C++ 高并发 (2025-12-26 00:49:30)
·C++ dll 设计接口时 (2025-12-26 00:49:28)
·透彻理解 C 语言指针 (2025-12-26 00:22:52)
·C语言指针详解 (经典 (2025-12-26 00:22:49)
·C 指针 | 菜鸟教程 (2025-12-26 00:22:46)