zoukankan      html  css  js  c++  java
  • c与c++程序连接问题 (转)

    它们之间的连接问题主要是因为c\c++编绎器对函数名译码的方式不能所引起的,考虑下面两个函数 
    /* c*/ 
    int strlen(char* string) 
    { ... } 
    //c++ 
    int strlen(char* string) 
    { ... } 
    两个函数完全一样。在c在函数是通过函数名来识别的,而在C++中,由于存在函数的重载问题,函数的识别方式通函数名,函数的返回类型,函数参数列表三者组合来完成的。因此上面两个相同的函数,经过C,C++编绎后会产生完全不同的名字。所以,如果把一个用c编绎器编绎的目标代码和一个用C++编绎器编绎的目标代码进行连接,就会出现连接失败的错误。
    解决的方法是使用extern C,避免C++编绎器按照C++的方式去编绎C函数 在头文件中定义: extern "C" int strlen(char* string) 或 extern "C" { int strlen(char* string) } 当C编绎器遇到extern "C"的时候就用传统的C函数编译方法对该函数进行编译。由于C编绎器不认识extern "C"这个编绎指令,而程序员又希望C,C++程序能共用这个头文件,因此通常在头文件中使用_cplusplus宏进行区分: 

    #if define _cplusplus 
    extern "C"{
    #endif
    int strlen(char* string)
    #ifdefine _cplusplus
    }
    #endif

     #define CALLBACK     __stdcall

     #define WINAPI       __stdcall
      那么,除了__stdcall,还有别的调用类型吗?究竟什么是调用类型呢?我的理解是:调用类型就是如何使用函数参数的一种规则。有三种调用类型:__fastcall__cdecl__stdcall
    1
    __cdecl调用类型:
       
    这是C的调用规则。对于所有非C++成员函数或未标有__stdcall__fastcall的函数来说,这是默认调用规则。
    2
    __fastcall调用类型:
       
    从字面意思可知,这是一种快速调用。因为CPU的寄存器会被使用来存放函数参数列表中的头几个参数。而剩下参数将被从右至左地推倒堆栈上。被调用函数将从 寄存器和堆栈获得函数参数。在x86中,ECXEDX一般被用来存放开始的参数。在.NET中,为了性能上的快速,就是使用ecxedx来实现 __fastcall的。
    3
    __stdcall调用类型:
       
    该调用只是通过堆栈来pushpop参数。push参数时,顺序是从右到左。

    现在,你应该明白了吧。最后,我带一句。三种调用类型在VC编译器中对应/Gd/Gr/Gz三个编译选项


    调用C/C++制做的DLL文件中导出函数的几点说明
    用某种语言调用C/C++制做的DLL文件中导出函数时,有几点注意:一、“_stdcall”的作用 
    C/C++中函数默认Calling Conventions(调用约定)是:
    参数由右向左压入栈,由调用者清空栈。,
    FORTRANPASCALVisualBASIC等语言中,函数的Calling Conventions是:
    参数由右向左压入栈,由被调函数清空栈。 

    那么在C/C++中使用_stdcall声明导出函数,就可以指定C/C++按照FORTRAN等的调用约定申明该函数,这时FORTRAN等其它语言中再调用这些函数就不会出现报错:run-time '49':Bad DLL call conventions. 

    二、加“extern "C"”的作用    
        extern "C" int _stdcall Extest();
       
    如上的原型,函数名符号会被VC编译器处理为 _Extest@0
        int _stdcall Extest();
       
    如上的原型,函数名符号会被VC编译器处理为 ?Extest@@YGXXZ
        C
    语言的编译链接环境不能处理第二种方式的修饰名,所以如果你的DLL要在CC++的环境下都适用,那么应该使用第一种命名方式。 

    例如:MFC的类中调用自己写的C函数,有时出现错误说无法找到函数的定义,原因是由于C C++的编译器对函数的修饰名不同,C++的修饰名中包括了各参数类型,因此通常情况下,C++程序无法找到C库中的函数,需要在声明C函数时加上 extern "C"的说明: 

    extern "C" void foo();
    C++
    编译器就会用C的修饰名方式来进行连接调用。同样,当C需要调用C++函数时,该C++函数也必须声明为extern "C"。通常可以在C的头文件里这样定义:

    #ifdef __cplusplus extern "C" { #endif ... #ifdef __cplusplus } #endif
    就可兼容CC++程序。

    原文链接:http://hi.baidu.com/yebihaigsino/blog/item/8efd3bd8ca21c8ee39012f0f.html

  • 相关阅读:
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    开源数据库在平安的应用实践
    从Oracle到PostgreSQL:Storage Index 特性 vs BRIN 索引
    Cosmos 白皮书
    基于支付场景下的微服务改造与性能优化
    MySQL数据库备份之主从同步配置
    Maven Gradle 区别
    荐书:《PostgreSQL指南:内幕探索》| 留言送书
    SQL、NoSQL、NewSQL,论开源之路谁主沉浮
  • 原文地址:https://www.cnblogs.com/xuangong/p/2122144.html
Copyright © 2011-2022 走看看