C# 与 C 类型对照速查表

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 输出句柄、输出指针

关键规则

  1. 所有句柄统一用 IntPtr,不用 int/uint(64 位程序地址会溢出);
  2. 无效句柄判断: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

重点说明

  1. 输入字符串 :单纯传入路径 / 文本用 string
  2. 输出字符串 (API 填充缓冲区)不能用 string ,必须 StringBuilder; 例:GetModuleFileNameW、GetWindowTextW;
  3. 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 写法

cpp 复制代码
typedef int (WINAPI *MsgBoxPtr)(HWND hWnd, LPCWSTR txt, LPCWSTR cap, UINT type);

C# 对应规则

  1. delegate 定义;
  2. 必须加特性 [UnmanagedFunctionPointer(CallingConvention.StdCall)]
  3. Windows API 统一 StdCall 调用约定,漏写会栈崩溃。

表格

C 类型 C# 实现
WINAPI 函数指针 标记 StdCall 的 delegate
LPVOID lpCallback IntPtr / delegate

C#

cpp 复制代码
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate int DlgMsgBox(IntPtr hWnd, string text, string cap, uint type);

C#

cpp 复制代码
IntPtr pFunc = GetProcAddress(hMod, "MessageBoxW");
DlgMsgBox fn = Marshal.GetDelegateForFunctionPointer<DlgMsgBox>(pFunc);

六、结构体 / 联合体(Windows 常用大结构)

通用映射规则

  1. C# 结构体加 [StructLayout(LayoutKind.Sequential)] 保持内存顺序;
  2. 有指针 / 句柄成员一律用 IntPtr
  3. 字符数组缓冲区用 fixed byte[]StringBuilder
C 结构示例 C# 处理方案
LARGE_INTEGER(联合体高低位) long(直接用 ulong/long 替代 QuadPart)
OVERLAPPED 异步 IO 结构体 自定义 Struct,Sequential 布局
SECURITY_ATTRIBUTES 自定义结构体,nLength 必须赋值

LARGE_INTEGER 简化对照(最常用)

C:

cpp 复制代码
typedef union _LARGE_INTEGER {
  struct { DWORD LowPart; LONG HighPart; };
  LONGLONG QuadPart;
} LARGE_INTEGER;

C# 直接简化:

cs 复制代码
// 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

cpp 复制代码
BOOL GetDiskFreeSpaceEx(LPCWSTR path, ULARGE_INTEGER* avail, ULARGE_INTEGER* total, ULARGE_INTEGER* free);

C#:

cs 复制代码
[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

九、高频易错坑总结

  1. DWORD 不要用 int:无符号数值,超过 21 亿会溢出;统一 uint;
  2. 句柄禁止用 int/long:64 位程序地址超 32 位,必须 IntPtr;
  3. 输出字符串不用 string,只用 StringBuilder;
  4. 宽字符 API 统一 CharSet.Unicode,解决中文路径乱码;
  5. 函数指针委托必须指定 StdCall,否则程序直接崩溃;
  6. 结构体不加 Sequential 会内存对齐错乱,读取数据错误;
  7. LoadLibrary / CreateFile 路径传中文,必须 W 版本 + Unicode 字符集。

C# 使用 [DllImport] 引入原生 Win32 API,分宽字符 W 版本(推荐,支持中文路径)

一、基础知识点

  1. [DllImport("kernel32.dll")]:从系统内核库导入 API
  2. CharSet = CharSet.Unicode = 调用 xxxW 宽字符版本,避免中文乱码
  3. StringBuilder 作为输出字符串缓冲区(C# string 不可修改,不能当输出参数)
  4. IntPtr 对应 C/C++ 里 HMODULE / HANDLE / void*

1. GetModuleFileNameW C# 实现(获取程序自身路径)

cs 复制代码
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

cs 复制代码
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)

cs 复制代码
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);
}

关键注意事项

  1. CharSet.Unicode 必须加 不加默认 Ansi,中文路径、中文参数会乱码。
  2. 输出字符串不能用 string,必须 StringBuilder 原生 API 要改写缓冲区,string 是只读。
  3. 函数名参数 GetProcAddress 传 ANSI 字符串 导出函数名字符串固定 ASCII,所以[DllImport]CharSet.Ansi
  4. 委托必须标记 [UnmanagedFunctionPointer(CallingConvention.StdCall)] Windows API 统一__stdcall 调用约定,漏写会栈失衡崩溃。
  5. 资源释放 LoadLibrary 后必须 FreeLibrary,避免内存泄漏。

4. C# 与 C 类型对照速查表

C/C++ 类型 C# 对应类型
HMODULE / HANDLE IntPtr
DWORD uint
LPCWSTR / LPWSTR string / StringBuilder
WINAPI 函数指针 delegate + Marshal.GetDelegateForFunctionPointer
BOOL bool