C#与C++互操作时的数据类型对应

C#和C++在互操作时,会涉及到数据类型对应的问题,如果数据类型用得不对,就会得不到想要的结果,严重的情况下,可能还会导致程序崩溃。这里做一下相关知识点的总结。

说明:

  1. 表格第一列是Visual C++中的数据类型,第二列是标准C中的数据类型

  2. 表格第三列括号中显示的是别名(关键字)。

  3. 关于使用string 还是StringBuilder ,可以参考P/Invoke各种总结(三、与字符串交互char*,wchar_t*) - zhaotianff - 博客园

VC++ Ansi C C#(CTS) 说明
VOID void System.Void(void) void类型,代表函数无返回值。在C++里函数无参数也可以传入void,在C#里不这么做。
HANDLE void * System.IntPtr or System.UIntPtr 长度:32位(32位系统), 64位(64位系统)
BYTE unsigned char System.Byte(byte) 长度:8位
SHORT short System.Int16(short) 长度:16位
WORD unsigned short System.UInt16(ushort) 长度:16 位
INT int System.Int32(int) 长度:32 位
UINT unsigned int System.UInt32(uint) 长度:32 位
LONG long System.Int32(int) 长度:32 位
BOOL long System.Boolean(bool) or System.Int32(int) 长度:32 位
DWORD unsigned long System.UInt32(uint) 长度:32 位
ULONG unsigned long System.UInt32(uint) 长度:32 位
CHAR char System.Char(char) 字符集:ANSI(多字节)
WCHAR wchar_t System.Char(char) 字符集:Unicode(宽字符)
LPSTR char * System.String(string) or System.Text.StringBuilder 字符集:ANSI(多字节)
LPCSTR const char * System.String(string) or System.Text.StringBuilder 字符集:ANSI(多字节)
LPWSTR wchar_t * System.String(string) or System.Text.StringBuilder 字符集:Unicode(宽字符)
LPCWSTR const wchar_t * System.String(string) or System.Text.StringBuilder 字符集:Unicode(宽字符)
FLOAT float System.Single(float) 长度:32 位
DOUBLE double System.Double(double) 长度:64 位
  1. 如果启用了"允许不安全代码",可以使用指针类型来代替**System.IntPtr** or System.UIntPtr

一般情况下,推荐使用**System.IntPtr or System.UIntPtr** 类,但是如果需要进行指针偏移,就一定要用指针类型,而不是**System.IntPtr** or System.UIntPtr

下面的示例代码将会说明第4点。

一、使用IntPtr的情况

使用C++创建共享内存并写入数据(示例代码,仅供参考)

复制代码
 1     RECT rect{ 100,100,100,100 };
 2     auto len = sizeof(rect);
 3 
 4     HANDLE m_handle = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, 0, MemorySize, "HelloWorld");
 5     if (m_handle != NULL)
 6     {
 7         PVOID m_pView = MapViewOfFile(m_handle, FILE_MAP_ALL_ACCESS, 0, 0, MemorySize);
 8         if (m_pView != NULL)
 9         {
10             memcpy_s(m_pView, MemorySize, (void *)&rect, len);        
11 
12             //程序退出时的资源释放操作
13             //.......
14         }
15     }

使用C#读出

复制代码
 1             IntPtr withoutOffsetPtr = OpenFileMapping(FILE_MAP_READ, false, "HelloWorld");
 2             IntPtr mapView = MapViewOfFile(withoutOffsetPtr, FILE_MAP_READ, 0, 0, MemorySize);
 3             Rect rect = new Rect();
 4             var size = Marshal.SizeOf(rect);
 5             IntPtr ptr = Marshal.AllocHGlobal(size);       //往IntPtr里拷贝数据需要提前分配空间,否则会报错
 6             byte[] buffer = new byte[size];
 7             Marshal.Copy(mapView, buffer, 0, size);        //先拷贝到字节数组
 8             Marshal.Copy(buffer, 0, ptr, size);            //再拷贝到IntPtr
 9             var obj = Marshal.PtrToStructure(ptr, typeof(Rect));  //将IntPtr转换成结构体
10             rect = (Rect)obj;
11 
12             Console.WriteLine($"Rect:left={rect.left},top={rect.top},right={rect.right},bottom={rect.bottom}");

二、使用指针的情况

使用C++创建共享内存并写入数据

复制代码
 1     RECT rect{ 10,10,10,10 };
 2     POINT point{ 3,3 };
 3     auto len = sizeof(rect);
 4 
 5     HANDLE m_handle = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, 0, MemorySize, "HelloWorld2");
 6     if (m_handle != NULL)
 7     {
 8         PVOID m_pView = MapViewOfFile(m_handle, FILE_MAP_ALL_ACCESS, 0, 0, MemorySize);
 9         if (m_pView != NULL)
10         {
11             //先写入rect
12             memcpy_s(m_pView, MemorySize,(void *)&rect, len);
13 
14             char* p = (char *)m_pView;
15             p = p + len;
16             m_pView = (void *)p;
17 
18             //再写入Point
19             memcpy_s(m_pView, MemorySize,(void *)&point, sizeof(point));
20             
21             //程序退出时的资源释放操作
22             //.......
23         }
24     }

使用C#读出(由于在写入Point数据时,指针的位置已经不是当初映射出来的起点了,要偏移,就需要使用指针)

复制代码
 1             //这一部分操作跟上面函数是一样的
 2             IntPtr withoutOffsetPtr = OpenFileMapping(FILE_MAP_READ, false, "HelloWorld2");
 3             IntPtr mapView = MapViewOfFile(withoutOffsetPtr, FILE_MAP_READ, 0, 0, MemorySize);
 4             Rect rect = new Rect();
 5             var size = Marshal.SizeOf(rect);
 6             IntPtr ptr = Marshal.AllocHGlobal(size);
 7             byte[] buffer = new byte[size];
 8             Marshal.Copy(mapView, buffer, 0, size);
 9             Marshal.Copy(buffer, 0, ptr, size);
10             var obj = Marshal.PtrToStructure(ptr, typeof(Rect));
11             rect = (Rect)obj;
12 
13             Console.WriteLine($"Rect:left={rect.left},top={rect.top},right={rect.right},bottom={rect.bottom}");
14 
15             //使用指针
16             unsafe
17             {
18                 byte* b = (byte*)mapView;
19                 b += size;
20                 mapView = (IntPtr)b;
21             }
22 
23             //读取Point结构的值
24             Point point = new Point();
25             size = Marshal.SizeOf(point);
26             ptr = Marshal.AllocHGlobal(size);
27             buffer = new byte[size];
28             Marshal.Copy(mapView, buffer, 0, size);
29             Marshal.Copy(buffer, 0, ptr, size);
30             obj = Marshal.PtrToStructure(ptr, typeof(Point));
31             point = (Point)obj;
32 
33             Console.WriteLine($"Point:x={point.x},y={point.y}");

示例代码

相关推荐
1白天的黑夜134 分钟前
动态规划-LCR 089.打家劫舍-力扣(LeetCode)
c++·算法·leetcode·动态规划
阳光_你好3 小时前
简单介绍C++中线性代数运算库Eigen
开发语言·c++·线性代数
ShineSpark3 小时前
C++面试3——const关键字的核心概念、典型场景和易错陷阱
c++·算法·面试
爱吃涮毛肚的肥肥(暂时吃不了版)5 小时前
仿腾讯会议——音频服务器部分
c++·qt·面试·职场和发展·音视频·腾讯会议
千亦学不会编程6 小时前
C# 枚举 详解
c#
DpHard6 小时前
自用Vscode 配置c++ debug环境
c++·ide·vscode
hy____1237 小时前
C++多态的详细讲解
开发语言·c++
superior tigre7 小时前
C++学习:六个月从基础到就业——C++20:范围(Ranges)进阶
c++·学习·c++20
小葡萄20257 小时前
黑马程序员C++2024版笔记 第0章 C++入门
开发语言·c++·笔记
万物此臻7 小时前
C#编写软件添加菜单栏
开发语言·c#