C#調(diào)用C++的實(shí)現(xiàn)步驟
1、內(nèi)存對(duì)齊的規(guī)則
(適用于C++、C#)
首先需要了解C++、C#的內(nèi)存對(duì)齊的規(guī)則:
結(jié)構(gòu)體的數(shù)據(jù)成員,第一個(gè)成員的偏移量為0,后面的每個(gè)數(shù)據(jù)成員存儲(chǔ)的起始位置要從自己大小的整數(shù)倍開始。
子結(jié)構(gòu)體中的第一個(gè)成員偏移量應(yīng)當(dāng)是子結(jié)構(gòu)體中最大成員的整數(shù)倍。
結(jié)構(gòu)體總大小必須是其內(nèi)部最大成員的整數(shù)倍。
以下為C#示例代碼:
internal class Program
{
struct Info
{
double dd;//32-40
bool bo;//40-48
}
struct MyStruct
{
char c;//0-1
decimal d;//8-16
int a;//16-20
double b;//24-32
Info info;//32-
}
static unsafe void Main(string[] args)
{
Console.WriteLine(sizeof(MyStruct));//輸出結(jié)果:48
}
}
2、調(diào)用約定
_cdecl稱之為c調(diào)用約定,參數(shù)從右至左的方式入棧,函數(shù)本身不清理?xiàng)?,此工作由調(diào)用者負(fù)責(zé),所以允許可變參數(shù)函數(shù)存在。我們自己編寫的程序一般為_cdecl
_stdcall稱之為標(biāo)準(zhǔn)調(diào)用約定,參數(shù)從右至左的方式入棧,函數(shù)本身清理?xiàng)?,所以不允許可變參數(shù)函數(shù)存在。windowsAPI一般為_stdcall
3、C#傳遞基本數(shù)據(jù)類型到C++
C++與C#的基本類型對(duì)應(yīng)關(guān)系如下表所示,數(shù)據(jù)通過值傳遞
| C++基本類型 | C#基本類型 |
|---|---|
| int | int |
| char | sbyte |
| short | short |
| float | float |
| double | double |
| long long | long |
| bool | bool |
| char* | string(傳值,需CharSet = CharSet.Ansi) |
| int*,double* | ref int,ref double |
| int&,double& | ref int,ref double |
**不要將C#中托管堆上的數(shù)據(jù),按照傳引用的方式傳遞到C++中 **
C++ 代碼
//native.h文件
extern "C"
{
__declspec(dllexport) void __cdecl TestBasicData(bool d1,char d2,short d3,
int d4,long long d5,float d6,double d8);
}
//native.cpp文件
#include "native.h"
void __cdecl TestBasicData(bool d1, char d2, short d3, int d4, long long d5, float d6, double d8)
{
return;//在此處添加斷點(diǎn),觀察在C#中的數(shù)據(jù)傳遞到了C++代碼中
}
C#代碼
[DllImport("NativeDll", CallingConvention = CallingConvention.Cdecl)]
public static extern int TestBasicData(bool d1, sbyte d2, short d3,
int d4, long d5, float d6, double d8);
static void Main(string[] args)
{
TestBasicData(true, 64, 128, 123456, 123456789, 12.45f, 3.142592);
}
注意:使用VS調(diào)試過程中,需要在C#工程中勾選啟動(dòng)本地代碼調(diào)試如下入所示,這樣調(diào)試的時(shí)候才會(huì)進(jìn)入C++代碼。

建議在VS的解決方案屬性中,將C#控制臺(tái)項(xiàng)目依賴C++的dll項(xiàng)目,如下入所示。這樣編譯C#項(xiàng)目會(huì)自動(dòng)編譯C++項(xiàng)目。

4、C#傳遞基本數(shù)據(jù)類型的數(shù)組到C++
**不要將C#中托管堆上的數(shù)據(jù),按照傳引用的方式傳遞到C++中 **
以下以傳遞int*為例
C++代碼如下,生成NativeDll.dll文件
//native.h文件
#pragma once
extern "C"
{
__declspec(dllexport) int __cdecl TestAddDoubles(int* d, int length);
}
//native.cpp文件
#include "native.h"
int __cdecl TestAddDoubles(int* d, int length)
{
int re = 0;
for (size_t i = 0; i < length; i++)
{
re += d[i];
d[i] = 99;//改變d地址內(nèi)的數(shù)據(jù),在C#代碼中也可以看到dpoint地址內(nèi)的數(shù)據(jù)被改為99
}
return re;
}
C#代碼如下
[DllImport("NativeDll", CallingConvention = CallingConvention.Cdecl)]
public static extern int TestAddDoubles(IntPtr d, int length);
static void Main(string[] args)
{
IntPtr dpoint = Marshal.AllocHGlobal(sizeof(int)*4);//在非托管內(nèi)存中創(chuàng)建4個(gè)int大小內(nèi)存的指針
unsafe
{
int* ptr = (int*)dpoint.ToPointer();
ptr[0] = 1;
ptr[1] = 3;
ptr[2] = 5;
ptr[3] = 7;
}
var re = TestAddDoubles(dpoint, 4);
Console.WriteLine(re);//輸出結(jié)果為16
Marshal.FreeHGlobal(dpoint);//非托管內(nèi)存需要在C#代碼中釋放
Console.ReadLine();
}
5、C#傳遞基本類型組成的結(jié)構(gòu)體給C++
5.1 按值傳遞基本類型組成的結(jié)構(gòu)體
**不要將C#中托管堆上的數(shù)據(jù),按照傳引用的方式傳遞到C++中 **
C++代碼如下
//native.h文件
extern "C"
{
struct Shape//注意:一定要與C#中的結(jié)構(gòu)體對(duì)齊方式一致
{
int x;
int y;
int z;
double area;
double volume;
};
__declspec(dllexport) int __cdecl TestStructor(Shape p);
}
//native.cpp文件
#include"native.h"
int __cdecl TestStructor(Shape p)
{
return sizeof(p);
}
C#代碼如下
struct Shape//注意:一定要與C++中的結(jié)構(gòu)體對(duì)齊方式一致
{
public int x;
public int y;
public int z;
public double area;
public double volume;
}
[DllImport("NativeDll", CallingConvention = CallingConvention.Cdecl)]
public static extern int TestStructor(Shape shape);
static void Main(string[] args)
{
Shape shape = new Shape() { x = 10, y = 20, z = 30, area = 123.45, volume = 3456.98 };
var len = TestStructor(shape);//傳值得方式將結(jié)構(gòu)體傳給C++
Console.WriteLine(len);
}
5.2 按引用傳遞基本類型組成的結(jié)構(gòu)體給C++結(jié)構(gòu)體指針
**不要將C#中托管堆上的數(shù)據(jù),按照傳引用的方式傳遞到C++中 **
C++代碼如下
//native.h文件
extern "C"
{
struct Shape//注意:一定要與C#中的結(jié)構(gòu)體對(duì)齊方式一致
{
int x;
int y;
int z;
double area;
double volume;
};
__declspec(dllexport) int __cdecl TestStructorPointer(Shape* p);
}
//native.cpp文件
#include"native.h"
int __cdecl TestStructorPointer(Shape* p)
{
int r = sizeof(*p);
p->x = 100;
p->y = 100;
p->z = 100;
p->area = 10.1;
p->volume = 10.1;
return r;
}
C#代碼如下
struct Shape//注意:一定要與C++中的結(jié)構(gòu)體對(duì)齊方式一致
{
public int x;
public int y;
public int z;
public double area;
public double volume;
}
[DllImport("NativeDll", CallingConvention = CallingConvention.Cdecl)]
public static extern int TestStructorPointer(ref Shape shape);
static void Main(string[] args)
{
Shape shape = new Shape() { x = 10, y = 20, z = 30, area = 123.45, volume = 3456.98 };
var len = TestStructorPointer(ref shape);//ref方式將結(jié)構(gòu)體傳給C++,通過斷點(diǎn)調(diào)試,查看C#中的shape也更改了
Console.WriteLine(len);
}
6、C#傳遞元素有數(shù)組的結(jié)構(gòu)體
**不要將C#中托管堆上的數(shù)據(jù),按照傳引用的方式傳遞到C++中 **
結(jié)構(gòu)體是按值進(jìn)行傳遞的。
C++代碼如下
//native.h文件
#pragma once
extern "C"
{
struct Student
{
char name[50];
int age;
double score;
};
__declspec(dllexport) int __cdecl TestStudentStructor(Student s);
}
//native.cpp文件
#include "native.h"
int __cdecl TestStudentStructor(Student s)
{
int len = sizeof(s);
return len;
}
C#中的結(jié)構(gòu)體映射到C++內(nèi)存中,要求結(jié)構(gòu)體只能包含非托管類型
C#代碼如下
unsafe struct Student//注意:一定要與C++中的結(jié)構(gòu)體對(duì)齊方式一致
{
public fixed byte name[50];
public int age;
public double score;
}
[DllImport("NativeDll", CallingConvention = CallingConvention.Cdecl)]
public static extern int TestStudentStructor(Student s);
static unsafe void Main(string[] args)
{
Student s = new Student();
s.age = 12;
s.score = 123.4;
var name = Encoding.GetEncoding("GB2312").GetBytes("abcd\0");//C++的字符串編碼為GB2312,結(jié)尾添加\0
Marshal.Copy(name, 0,new IntPtr(s.name),name.Length);
var len = TestStudentStructor(s);
Console.WriteLine(len);
}
7、C#傳遞元素有數(shù)組的結(jié)構(gòu)體指針
** 不要將C#中托管堆上的數(shù)據(jù),按照傳引用的方式傳遞到C++中 **
C++代碼如下
//native.h文件
#pragma once
extern "C"
{
struct Student
{
char name[50];//結(jié)構(gòu)體中含有char數(shù)組
int age;
double score;
};
__declspec(dllexport) int __cdecl TestStudentStructorPointer(Student* s);
}
//native.cpp文件
#include "native.h"
int __cdecl TestStudentStructorPointer(Student* s)//C++中改變s,C#中也會(huì)變
{
int len = sizeof(*s);
s->age = 1000;
s->score = 1000.0;
for (size_t i = 0; i < sizeof(s->name); i++)
{
s->name[i] = 123;
}
return len;
}
C#中的結(jié)構(gòu)體映射到C++內(nèi)存中,要求結(jié)構(gòu)體只能包含非托管類型
C#代碼如下
unsafe struct Student//注意:一定要與C++中的結(jié)構(gòu)體對(duì)齊方式一致
{
public fixed byte name[50];
public int age;
public double score;
}
[DllImport("NativeDll", CallingConvention = CallingConvention.Cdecl)]
public static extern int TestStudentStructorPointer(ref Student s);//使用ref
static void Main(string[] args)
{
Student s = new Student();
s.age = 12;
s.score = 123.4;
var name = Encoding.GetEncoding("GB2312").GetBytes("abcd\0");//結(jié)尾添加\0
unsafe
{
Marshal.Copy(name, 0, new IntPtr(s.name), name.Length);
}
var len = TestStudentStructorPointer(ref s);//ref方式將結(jié)構(gòu)體傳給C++,通過斷點(diǎn)查看C#中的s也更改了
Console.WriteLine(len);
}到此這篇關(guān)于C#調(diào)用C++的實(shí)現(xiàn)步驟的文章就介紹到這了,更多相關(guān)C#調(diào)用C++內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#實(shí)現(xiàn)塊狀鏈表的項(xiàng)目實(shí)踐
這篇文章主要介紹了C#實(shí)現(xiàn)塊狀鏈表的項(xiàng)目實(shí)踐,通過定義塊和鏈表類,利用塊內(nèi)元素引用實(shí)現(xiàn)塊與塊之間的鏈接關(guān)系,從而實(shí)現(xiàn)對(duì)塊狀鏈表的遍歷、插入和刪除等操作,感興趣的可以了解一下2023-11-11
C#中OpenCVSharp實(shí)現(xiàn)輪廓檢測(cè)
這篇文章主要介紹了C#中OpenCVSharp實(shí)現(xiàn)輪廓檢測(cè),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
C#控制臺(tái)帶參數(shù)程序源碼編寫實(shí)例講解
像ipconfig /all 這樣的CMD命令想必大家都知道,但是很多童鞋可能不知道怎么寫這樣的控制臺(tái)帶參數(shù)的程序,需要的朋友可以了解下2012-12-12

