C# 与 C 类型对照速查表
一、基础数值类型(无符号 / 有符号整数)
| C/C++ 原生类型 | Windows 宏别名 | 占用字节 | C# 对应类型 | 说明 |
|---|---|---|---|---|
| char | CHAR | 1 | sbyte / byte | char 有符号;unsigned char = byte |
| unsigned char | UCHAR, BYTE | 1 | byte | BYTE=unsigned char,0~255 |
| short | SHORT | 2 | short | 16 位有符号 |
| unsigned short | USHORT, WORD | 2 | ushort | WORD,0~65535 |
| int | INT | 4 | int | 32 位有符号 |
| unsigned int | UINT | 4 | uint | 32 位无符号 |
| long | LONG | 4 | int | Windows 下 long 固定 4 字节 |
| unsigned long | ULONG, DWORD | 4 | uint | DWORD=ULONG 0~0xFFFFFFFF |
| long long | LONGLONG | 8 | long | 64 位有符号 |
| unsigned long long | ULONGLONG, DWORDLONG | 8 | ulong | 64 位无符号大容量数值 |
| float | FLOAT | 4 | float | 单精度浮点 |
| double | DOUBLE | 8 | double | 双精度浮点 |
特殊常量对照
INVALID_FILE_ATTRIBUTES = (DWORD)-1→ C#public const uint INVALID_FILE_ATTRIBUTES = 0xFFFFFFFF;INVALID_HANDLE_VALUE = (HANDLE)-1→ C#IntPtr(-1)
二、句柄、指针类(内核对象 / 内存地址)
| C/C++ 类型 | 含义 | C# 类型 | 使用说明 |
|---|---|---|---|
| void* | 通用指针 | IntPtr | 万能指针,存放地址 |
| HANDLE | 内核对象句柄(文件、线程、进程、事件) | IntPtr | CreateFile、OpenProcess 返回 |
| HMODULE | DLL/EXE 模块句柄 | IntPtr | LoadLibrary 返回 |
| HWND | 窗口句柄 | IntPtr | FindWindow、MessageBox 窗口参数 |
| HDC | 绘图设备上下文 | IntPtr | GDI 绘图 API |
| HBITMAP / HPEN / HBRUSH | GDI 资源句柄 | IntPtr | 位图、画笔、画刷 |
| HINSTANCE | 程序实例句柄 | IntPtr | 等价 HMODULE |
| LPVOID / LPCVOID | 通用读写缓冲区指针 | IntPtr / byte[] | ReadFile/WriteFile 数据缓冲区 |
| LPVOID* | 指针的指针 | out IntPtr | 输出句柄、输出指针 |
关键规则
- 所有句柄统一用
IntPtr,不用int/uint(64 位程序地址会溢出); - 无效句柄判断:
if (h == IntPtr.Zero || h == (IntPtr)(-1))。
三、字符串类型(ANSI / Unicode 宽字符,重点易错)
| C/C++ 类型 | 编码 | C# 入参类型 | C# 输出参数 | DllImport CharSet 配置 |
|---|---|---|---|---|
| LPCSTR / LPSTR | GBK ANSI 单字节 | string | StringBuilder | CharSet.Ansi |
| LPCWSTR / LPWSTR | UTF16 宽字符(xxxW) | string | StringBuilder | CharSet.Unicode |
| TCHAR / LPTSTR | 自适应 | string | StringBuilder | CharSet.Auto |
重点说明
- 输入字符串:单纯传入路径 / 文本用
string; - 输出字符串(API 填充缓冲区)不能用 string,必须
StringBuilder; 例:GetModuleFileNameW、GetWindowTextW; - GetProcAddress 函数名参数是 ANSI:
[DllImport(..., CharSet.Ansi)]。
四、布尔类型
| C/C++ | 说明 | C# 类型 | 注意 |
|---|---|---|---|
| BOOL | int 底层,TRUE=1,FALSE=0 | bool / int | 推荐 bool,非 0 自动 true |
| BOOLEAN | BYTE 1 字节布尔 | byte | 极少 API 使用 |
五、函数指针 / 回调(DLL 动态调用、窗口回调)
C 写法
typedef int (WINAPI *MsgBoxPtr)(HWND hWnd, LPCWSTR txt, LPCWSTR cap, UINT type);C# 对应规则
- 用
delegate定义; - 必须加特性
[UnmanagedFunctionPointer(CallingConvention.StdCall)]; - Windows API 统一
StdCall调用约定,漏写会栈崩溃。
表格
| C 类型 | C# 实现 |
|---|---|
| WINAPI 函数指针 | 标记 StdCall 的 delegate |
| LPVOID lpCallback | IntPtr / delegate |
C#
[UnmanagedFunctionPointer(CallingConvention.StdCall)] public delegate int DlgMsgBox(IntPtr hWnd, string text, string cap, uint type);C#
IntPtr pFunc = GetProcAddress(hMod, "MessageBoxW"); DlgMsgBox fn = Marshal.GetDelegateForFunctionPointer<DlgMsgBox>(pFunc);六、结构体 / 联合体(Windows 常用大结构)
通用映射规则
- C# 结构体加
[StructLayout(LayoutKind.Sequential)]保持内存顺序; - 有指针 / 句柄成员一律用
IntPtr; - 字符数组缓冲区用
fixed byte[]或StringBuilder;
| C 结构示例 | C# 处理方案 |
|---|---|
| LARGE_INTEGER(联合体高低位) | long(直接用 ulong/long 替代 QuadPart) |
| OVERLAPPED 异步 IO 结构体 | 自定义 Struct,Sequential 布局 |
| SECURITY_ATTRIBUTES | 自定义结构体,nLength 必须赋值 |
LARGE_INTEGER 简化对照(最常用)
C:
typedef union _LARGE_INTEGER { struct { DWORD LowPart; LONG HighPart; }; LONGLONG QuadPart; } LARGE_INTEGER;C# 直接简化:
// GetFileSizeEx 直接传 out long 替代结构体 [DllImport("kernel32.dll")] public static extern bool GetFileSizeEx(IntPtr hFile, out long lpFileSize);七、指针输出参数(带 LP 前缀,输出值)
C 原型:BOOL GetXXX(DWORD* outValue);
| C 参数 | C# 修饰符 | 示例 |
|---|---|---|
| LPDWORD / DWORD* | out uint | out uint dwOut |
| LPULONGLONG / ULONGLONG* | out ulong | out ulong llOut |
| LPHANDLE / HANDLE* | out IntPtr | out IntPtr hOut |
| LPBOOL / BOOL* | out bool | out bool bRet |
c
BOOL GetDiskFreeSpaceEx(LPCWSTR path, ULARGE_INTEGER* avail, ULARGE_INTEGER* total, ULARGE_INTEGER* free);C#:
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)] public static extern bool GetDiskFreeSpaceEx(string path, out long avail, out long total, out long free);八、调用约定对照表
| C 宏 | 调用约定 | C# 委托标记 | 使用场景 |
|---|---|---|---|
| WINAPI / __stdcall | StdCall | CallingConvention.StdCall | 所有 Windows 系统 API(默认) |
| __cdecl | Cdecl | CallingConvention.Cdecl | C 标准库、第三方自定义 DLL |
九、高频易错坑总结
- DWORD 不要用 int:无符号数值,超过 21 亿会溢出;统一 uint;
- 句柄禁止用 int/long:64 位程序地址超 32 位,必须 IntPtr;
- 输出字符串不用 string,只用 StringBuilder;
- 宽字符 API 统一
CharSet.Unicode,解决中文路径乱码; - 函数指针委托必须指定 StdCall,否则程序直接崩溃;
- 结构体不加 Sequential 会内存对齐错乱,读取数据错误;
- LoadLibrary / CreateFile 路径传中文,必须 W 版本 + Unicode 字符集。
C# 使用[DllImport]引入原生 Win32 API,分宽字符 W 版本(推荐,支持中文路径)
一、基础知识点
[DllImport("kernel32.dll")]:从系统内核库导入 APICharSet = CharSet.Unicode= 调用 xxxW 宽字符版本,避免中文乱码StringBuilder作为输出字符串缓冲区(C# string 不可修改,不能当输出参数)IntPtr对应 C/C++ 里HMODULE / HANDLE / void*
1. GetModuleFileNameW C# 实现(获取程序自身路径)
using System; using System.Text; using System.Runtime.InteropServices; class Win32Helper { // 导入API [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] public static extern uint GetModuleFileNameW( IntPtr hModule, // NULL=0 取当前EXE StringBuilder lpFilename, uint nSize ); static void Main() { StringBuilder sbPath = new StringBuilder(1024); uint ret = GetModuleFileNameW(IntPtr.Zero, sbPath, (uint)sbPath.Capacity); if (ret > 0) { Console.WriteLine("程序完整路径:" + sbPath.ToString()); // 截取目录(去掉exe文件名) string dir = System.IO.Path.GetDirectoryName(sbPath.ToString()); Console.WriteLine("程序目录:" + dir); } else { Console.WriteLine("获取失败"); } Console.ReadKey(); } }2. LoadLibraryW + GetProcAddress + FreeLibrary C# 动态调用 DLL
模拟 C 里动态加载 user32 调用 MessageBoxW
using System; using System.Runtime.InteropServices; class DllInvokeDemo { // 1. 加载释放DLL [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] public static extern IntPtr LoadLibraryW(string lpLibFileName); [DllImport("kernel32.dll", CharSet = CharSet.Ansi)] // 函数名是ASCII public static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName); [DllImport("kernel32.dll")] public static extern bool FreeLibrary(IntPtr hModule); // 2. 定义MessageBoxW委托(对应C函数指针) [UnmanagedFunctionPointer(CallingConvention.StdCall)] public delegate int DlgMsgBox(IntPtr hWnd, string text, string caption, uint type); static void Main() { // 加载user32.dll IntPtr hUser32 = LoadLibraryW("user32.dll"); if (hUser32 == IntPtr.Zero) { Console.WriteLine("加载DLL失败"); return; } // 获取MessageBoxW地址 IntPtr pMsgBox = GetProcAddress(hUser32, "MessageBoxW"); if (pMsgBox == IntPtr.Zero) { FreeLibrary(hUser32); return; } // 转为委托调用 DlgMsgBox msgBox = Marshal.GetDelegateForFunctionPointer<DlgMsgBox>(pMsgBox); msgBox(IntPtr.Zero, "C#调用Win32 API弹窗", "提示", 0); // 释放库 FreeLibrary(hUser32); Console.ReadKey(); } }3. 常用配套 API 补充(GetFileAttributesW / INVALID_FILE_ATTRIBUTES)
public const uint INVALID_FILE_ATTRIBUTES = 0xFFFFFFFF; [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] public static extern uint GetFileAttributesW(string lpFileName); // 使用 uint attr = GetFileAttributesW(@"D:\test.txt"); if (attr == INVALID_FILE_ATTRIBUTES) { Console.WriteLine("文件不存在/无法访问"); } else { bool isHidden = (attr & 2) != 0; // FILE_ATTRIBUTE_HIDDEN = 2 Console.WriteLine("是否隐藏:" + isHidden); }关键注意事项
- CharSet.Unicode 必须加不加默认 Ansi,中文路径、中文参数会乱码。
- 输出字符串不能用
string,必须StringBuilder原生 API 要改写缓冲区,string 是只读。 - 函数名参数
GetProcAddress传 ANSI 字符串 导出函数名字符串固定 ASCII,所以[DllImport]写CharSet.Ansi。 - 委托必须标记
[UnmanagedFunctionPointer(CallingConvention.StdCall)]Windows API 统一__stdcall 调用约定,漏写会栈失衡崩溃。 - 资源释放
LoadLibrary后必须FreeLibrary,避免内存泄漏。
4. C# 与 C 类型对照速查表
| C/C++ 类型 | C# 对应类型 |
|---|---|
| HMODULE / HANDLE | IntPtr |
| DWORD | uint |
| LPCWSTR / LPWSTR | string / StringBuilder |
| WINAPI 函数指针 | delegate + Marshal.GetDelegateForFunctionPointer |
| BOOL | bool |