C程序如何调用C++接口?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C程序如何调用C++接口?相关的知识,希望对你有一定的参考价值。

就是我整个程序都是C++结构,但是有个模块只能是C实现,而这个模块需要调用其余C++编写的模块,请问该如何实现?

如果 你的这个C模块,能够在你的整个程序所以的IDE编译C++环境下能够 编译通过 。

那你的这个C模块就可以调用其它的C++类模块。所要做的工作就是把模块的头文件、资源包含进来。
参考技术A 你用能编译C++的编译器一般也能编译C,只要需要的头文件都包含进来直接混合着写就行 参考技术B 在一个编译器里面可以通用的,但是都要有相应的头文件追问

可以给个例子吗?谢谢了

追答

没关系,你直接写c++代码,这些不影响编译,看我的这个程序中的一部分
#include
#include
using namespace std;
..........
cout<<"\n\n\n\n\n\n\n\t\t*----------------------------------------*"<<endl;
printf("\t\t* 1.程序代码 *\n");
.........

参考技术C class A


...

//内部变量
private:
INT m_nCount;
CString m_sName;

//接口函数
public:
INT GetItemCount() ;
CString GetName() ;
VOID SetItemCount( INT nCount ) ;
VOID SetName( CString sNewName ) ;

...
;
参考技术D 将 C++ 函数声明为``extern "C"''(在你的 C++ 代码里做这个声明),然后调用它(在你的 C 或者 C++ 代码里调用)。例如:
// C++ code:
extern "C" void f(int);
void f(int i)

// ...


然后,你可以这样使用 f():
/* C code: */
void f(int);
void cc(int i)

f(i);
/* ... */


当然,这招只适用于非成员函数。如果你想要在 C 里调用成员函数(包括虚函数),则需要提供一个简单的包装(wrapper)。例如:
// C++ code:
class C

// ...
virtual double f(int);
;

extern "C" double call_C_f(C* p, int i) // wrapper function

return p->f(i);


然后,你就可以这样调用 C::f():
/* C code: */
double call_C_f(struct C* p, int i);

void ccc(struct C* p, int i)

double d = call_C_f(p,i);
/* ... */


如果你想在 C 里调用重载函数,则必须提供不同名字的包装,这样才能被 C 代码调用。例如:
// C++ code:
void f(int);
void f(double);

extern "C" void f_i(int i) f(i);
extern "C" void f_d(double d) f(d);

然后,你可以这样使用每个重载的 f():
/* C code: */
void f_i(int);
void f_d(double);

void cccc(int i,double d)

f_i(i);
f_d(d);
/* ... */

注意,这些技巧也适用于在 C 里调用 C++ 类库,即使你不能(或者不想)修改 C++ 头文件。
第5个回答  2011-09-13 C++包含C,什么叫C调用C++接口?追问

就是我整个程序都是C++结构,但是有个模块只能是C实现,而这个模块需要调用其余C++编写的模块,请问该如何实现?

追答

用C++里可以用C语言,你用什么ide的?

非托管C++通过C++/CLI包装调用C# DLL

项目中要给其它客户程序提供DLL做为接口,该项目是在.Net4.0平台下开发。终所周知.Net的各个版本之间存在着兼容性的问题,但是为了使用高版本运行平台的新特性,又不得不兼顾其它低版本平台客户程序的调用。为了解决这个问题尝试通过一个C++/CLI DLL对高版本的.Net DLL的接口加了一层包装,对外暴露C风格的接口给客户程序调用。

可支持的客户语言平台:

  • VB 6.0
  • VC++
  • .Net 1.0/.Net 1.1
  • .Net 2.0
  • .Net 3.5

 

 创建C# .Net4.0的类库

  • 创建一个C#项目:Csharp

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Csharp
{
    public class CsharpClass
    {
        public int DoTesting(int x, int y, string testing, out string error)
        {
            error = testing + " -> testing is ok.";
            return x + y;
        }
    }
}

 

创建C++/CLI包装类库

  • 创建项目C++/CLI项目:CsharpWrap

  • 添加对Csharp的引用

  • CsharpWrap.h

// CsharpWrap.h

#pragma once

#include <windows.h>  
#include <string> 

using namespace System;
using namespace Csharp;
using namespace std;
using namespace Runtime::InteropServices;
  • CsharpWrap.cpp

// This is the main DLL file.

#include "stdafx.h"

#include "CsharpWrap.h"

extern "C" _declspec(dllexport) int DoTesting(int x, int y, char* testing, char* error)
{
    try
    {
        CsharpClass ^generator = gcnew CsharpClass();
        String^ strTesting = gcnew String(testing);
        String^ strError;

        int sum = generator->DoTesting(x, y,strTesting, strError);

        if(strError != nullptr)
        {
            char* cError = 
                (char*)(Marshal::StringToHGlobalAnsi(strError)).ToPointer();
            memcpy(error,cError,strlen(cError) + 1);
        }
        else
        {
            error = nullptr;
        }

        return sum;
    }
    catch(exception e)
    {
        memcpy(error,e.what(),strlen(e.what()) + 1);
        return -1;
    }
}
  • 项目输出和使用

  1. Csharp.dll
  2. CsharpWrap.dll

如果要调用CsharpWrap.dll必须保证Csharp.dll也被调用程序可见(即应该放在进程EXE文件同一目录下)

 

调用Demo代码

  • C++

HINSTANCE hInst= LoadLibrary(_T("CsharpWrap.dll"));
if(hInst)
{
    pfunc DoTesting = (pfunc)GetProcAddress(hInst,"DoTesting");

    if(DoTesting)
    {
        char error[100]= {NULL};
        int sum = DoTesting(1, 2, "Hello", error);
        //show testing results
        char strSum[8];
        _itoa_s(sum,strSum,16);
        ::MessageBoxA(NULL, error, strSum, MB_OK);
    }
    else
    {
        ::MessageBoxA(NULL, "Get function fail.", "Fail", MB_OK);
    }
    //free library
    FreeLibrary(hInst);
    hInst = nullptr;
}
else
{
    ::MessageBoxA(NULL, "Load dll fail.", "Fail", MB_OK);
}
  • C#低版本.Net

导出函数

[DllImport("CsharpWrap.dll")]
static extern int DoTesting(int x, int y, string testing, StringBuilder error);

调用

StringBuilder sb = new StringBuilder(200);
int sum  = DoTesting(1, 2, "Hellow", sb);
MessageBox.Show(sb.ToString(), sum.ToString());
  • VB6.0

导出函数

Public Declare Function DoTesting Lib "CsharpWrap.dll" (ByVal x As Integer, ByVal y As Integer, ByVal testing As String, ByVal error As String) As Integer

调用

Dim error As String
Dim testing As String
Dim x As Integer
Dim y As Integer
Dim sum As Integer

testing = "Hello"
error = String(60000, vbNullChar)
sum = DoTesting(x, y, testing, error)

 

常见问题及注意事项

  • 平台工具集的问题

如果使用的是VS2010以上的版本编译出来的C++/CLI DLL可能会遇到缺少依赖等运行错误。

如果要支持XP系统工具集尽量用_xp结尾的

平台工具集的依赖DLL,把下面的或其它相应版本的依赖DLL放到目标机器的C:\\WINDOWS\\SYSTEM32下

      1. msvcp100.dll
      2. msvcr100.dll
      3. msvcp110.dll
      4. msvcr110.dll

 

  • 字符集的问题,因为.Net默认用的字符集是Unicode,但是客户程序有可能是其它字符集,这样也可能会造成字符串在程序间的兼容问题。

可选择Unicode/Multi-Byte,根据不项目需求选择相应的字符集

代码内对不同字符集进行转换

从char* to 宽字符

wchar_t *GetWC(const char *c)
{
    const size_t cSize = strlen(c)+1;
    wchar_t* wc = new wchar_t[cSize];
    MultiByteToWideChar(CP_ACP,0,(const char *)c,int(cSize),wc,int(cSize));    
    return wc;
}

String^ to Char*

char* cError = (char*)(Marshal::StringToHGlobalAnsi(strError)).ToPointer();

 

  • 调用的C++/CLI DLL的时候传入参数的问题

C#调用的时候String参数对应的类型应该是StringBuilder,要注意StringBuilder的容量,默认是256个字符,如果返回的比较多的东西要注意初始化相应大小的容量。

 

  • DLL多层嵌套的问题

如果用LoadLibrary加载DLL失败,可以尝试用LoadLibraryEx,同时保证所依赖的C#DLL放到进程EXE同级目录。

LoadLibraryEx("DLL绝对路径", NULL, LOAD_WITH_ALTERED_SEARCH_PATH);

 

转载请注明出处:http://www.cnblogs.com/keitsi/p/5554110.html

以上是关于C程序如何调用C++接口?的主要内容,如果未能解决你的问题,请参考以下文章

C语言或者C++如何调用一个http接口并得到返回结果?

非托管C++通过C++/CLI包装调用C# DLL

Java程序通过JNI调用C++程序的方法

C++中是如何调用C接口的?

python 调用c++程序, c++程序如何返回数组给python

Hadoop下怎么使用C程序啊?或者说,怎么使用C调用Hadoop的接口来编写程序呢?