zoukankan      html  css  js  c++  java
  • C++调用C链接库会出现的问题 拂晓风起

    (非本人原创,在此注明,以表对原作者的敬佩http://blog.163.com/sean_1010/blog/static/11080322200952633111975/

     

    以下是假设旧的C程序库

    C的头文件

    /*-----------c.h--------------*/

    #ifndef _C_H_

    #define _C_H_

    extern int add(int x, int y);

    #endif

    C的源文件

    /*-----------c.c--------------*/

    int add(int x, int y){

    return x+y;

    }

    C++的调用

    /*-----------cpp.cpp--------------*/

    #include "c.h"

    void main()

    {

    add(1, 0);

    }

    这样编译会产生错误cpp.obj : error LNK2001: unresolved external symbol "int __cdecl add(int,int)" ([email=?add@@YAHHH@Z]?add@@YAHHH@Z[/email]),原因是找不到add的目标模块

    这才令我想起C++重载的函数命名方式和C函数的命名方式,让我们回顾一下:C中函数编译后命名会在函数名前加以"_",比如add函数编译成obj文件时的实际命名为_add,而c++命名则不同,为了实现函数重载同样的函数名add因参数的不同会被编译成不同的名字

    例如

    int add(int , int)==>add@@YAHHH@Z,

    float add(float , float )==>add@@YAMMM@Z,

    以上是VC6的命名方式,不同的编译器会不同,总之不同的参数同样的函数名将编译成不同目标名,以便于函数重载是调用具体的函数。

    编译cpp.cpp中编译器在cpp文件中发现add(1, 0);的调用而函数声明为extern int add(int x, int y);编译器就决定去找[email=add@@YAHHH@Z]add@@YAHHH@Z[/email],可惜他找不到,因为C的源文件把extern int add(int x, int y);编译成_add了;

    为了解决这个问题C++采用了extern "C",这就是我们的主题,想要利用以前的C程序库,那么你就要学会它,我们可以看以下标准头文件你会发现,很多头文件都有以下的结构

    #ifndef __H

    #define __H

    #ifdef __cplusplus

    extern "C" {

    #endif

    extern int f1(int, int);

    extern int f2(int, int);

    extern int f3(int, int);

    #ifdef __cplusplus

    }

    #endif

    #endif /*__H*/

    如果我们仿制该头文件可以得到

    #ifndef _C_H_

    #define _C_H_

    #ifdef __cplusplus

    extern "C" {

    #endif

    extern int add(int, int);

    #ifdef __cplusplus

    }

    #endif

    #endif /* _C_H_ */

    这样编译

    /*-----------c.c--------------*/

    int add(int x, int y){

    return x+y;

    }

    这时源文件为*.c,__cplusplus没有被定义,extern "C" {}这时没有生效对于C他看到只是extern int add(int, int);

    add函数编译成_add(int, int);

    而编译c++源文件

    /*-----------cpp.cpp--------------*/

    #include "c.h"

    void main()

    {

    add(1, 0);

    }

    这时源文件为*.cpp,__cplusplus被定义,对于C++他看到的是extern "C" {extern int add(int, int);}编译器就会知道 add(1, 0);调用的C风格的函数,就会知道去c.obj中找_add(int, int)而不是[email=add@@YAHHH@Z]add@@YAHHH@Z[/email];

    这也就为什么DLL中常看见extern "C" {},windows是采用C语言编制他首先要考虑到C可以正确调用这些DLL,而用户可能会使用C++而extern "C" {}就会发生作用

    当原来的C语言写的头文件里面没有考虑这个问题的时候,可以写成这样:

    #include <XXXXX.h>

    #include <YYYYY.h>

    extern "C" {

    #include "sift.h"

    #include "imgfeatures.h"

    #include "kdtree.h"

    #include "utils.h"

    #include "xform.h"

    }

    这样就可以在C++里面用别人写的C语言的东西了。

    kenkofox@qq.com https://github.com/kenkozheng 欢迎投简历给我,一线大厂工作机会
  • 相关阅读:
    poj 3321 Apple Tree
    hdu 1520 Anniversary party
    Light OJ 1089 Points in Segments (II)
    Timus 1018 Binary Apple Tree
    zoj 3299 Fall the Brick
    HFUT 1287 法默尔的农场
    Codeforces 159C String Manipulation 1.0
    GraphQL + React Apollo + React Hook 大型项目实战(32 个视频)
    使用 TypeScript & mocha & chai 写测试代码实战(17 个视频)
    GraphQL + React Apollo + React Hook + Express + Mongodb 大型前后端分离项目实战之后端(19 个视频)
  • 原文地址:https://www.cnblogs.com/kenkofox/p/1597053.html
Copyright © 2011-2022 走看看