开发工具运维【免费下载链接】gopsutilpsutil for golang项目地址https://gitcode.com/gh_mirrors/go/gopsutil点击查看免费下载导读本文以 gopsutil 仓库根目录下的 windows_memo.rst 为核心系统梳理 Windows API 中最常用的 15 种基础数据类型DWORD、LONGLONG、SIZE_T、LONG_PTR 等的位宽定义并结合仓库中cpu、mem、host、process、net、disk等模块的 Windows 实现源码讲解这些 C 类型在 Go 语言golang.org/x/sys/windows中的对应映射、结构体布局写法与内存对齐陷阱。读完本文你将能读懂 gopsutil 的 Windows 底层实现并具备为 Windows API 编写正确结构体布局的实战能力。一、备忘录的背景为什么 gopsutil 需要一份 Windows 类型速查表gopsutil 是一个用 Go 编写的跨平台系统信息采集库psutil for golang其 README.md 明确说明它designed to work across multiple platforms。Windows 平台的实现无法像 Linux 那样直接解析/proc伪文件系统而必须通过kernel32.dll、ntdll.dll、psapi.dll、pdh.dll、iphlpapi.dll等动态库导出函数Win32/PDH/WMI来获取 CPU、内存、磁盘、网络、进程等信息。调用这些 C 语言 API 的前提是把 C 结构体按内存布局精确地翻译成 Go 结构体。例如读取系统内存信息需要 MEMORYSTATUSEX 结构体读取 CPU 时间需要 SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION 结构体读取进程基本信息需要 PROCESS_BASIC_INFORMATION 结构体。windows_memo.rst 正是为这一工作准备的手边速查卡它只回答一个问题——这个 Windows 类型到底占多少位、是有符号还是无符号、在不同位宽_WIN64下如何变化。这些信息直接决定了 Go 结构体里应该写uint32、uint64还是uintptr。二、完整类型清单原备忘录全部 15 种类型下面是 windows_memo.rst 中记录的全部类型定义按无符号 / 有符号 / 指针精度 / 特殊分类整理定义部分与原文完全一致2.1 无符号整数类型类型位宽与定义DWORD32-bit unsigned integer32 位无符号整数DWORDLONG64-bit unsigned integer64 位无符号整数DWORD3232-bit unsigned integer32 位无符号整数DWORD6464-bit unsigned integer64 位无符号整数WORD16-bit unsigned integer16 位无符号整数SIZE_Tmaximum number of bytes to which a pointer can point. typedef ULONG_PTR SIZE_T指针所能指向的最大字节数即指针精度大小的无符号整数2.2 有符号整数类型类型位宽与定义INT32-bit signed integer32 位有符号整数LONG32-bit signed integer32 位有符号整数LONGLONG64-bit signed integer64 位有符号整数SHORT16-bit integer16 位整数未标注符号实践中常作为有符号使用SSIZE_Tsigned version of SIZE_T. typedef LONG_PTR SSIZE_TSIZE_T 的有符号版本指针精度大小2.3 指针精度类型随 _WIN64 切换位宽类型位宽与定义DWORD_PTRunsigned long type for pointer precision指针精度的无符号长整型HALF_PTR_WIN64 int, else short64 位下为 int否则为 shortINT_PTR_WIN64 __int64 else int64 位下为 __int64否则为 intLONG_PTR_WIN64 __int64 else long64 位下为 __int64否则为 long记忆要点这 15 种类型中带PTR后缀的四个类型DWORD_PTR、HALF_PTR、INT_PTR、LONG_PTR以及SIZE_T/SSIZE_T是位宽随平台变化的在 32 位系统上是 32 位在 64 位系统上是 64 位其余类型位宽固定。这正是 Go 中uintptr与之对应的根本原因。三、Go 语言中的类型映射从 C 定义到 Go 代码备忘录记录的是 C 侧的定义而 gopsutil 是 Go 项目因此在仓库源码中这些类型以 Go 原生类型呈现。结合 go.mod 中依赖的golang.org/x/sys v0.48.0即golang.org/x/sys/windows包映射关系如下Windows 类型对应 Go 类型说明DWORD / DWORD32 / INT / LONGuint32/int32固定 32 位DWORDLONG / DWORD64 / LONGLONGuint64/int64固定 64 位WORD / SHORTuint16/int16固定 16 位DWORD_PTR / INT_PTR / LONG_PTR / SIZE_T / SSIZE_T / HALF_PTRuintptr/int指针精度位宽随平台变化Go 的uintptr恰好就是足够容纳一个指针的无符号整数布尔型返回值uintptr或int32Windows API 返回 BOOL通常用返回值的 0/非 0 判断成败这条映射关系在仓库源码中可以得到充分验证下面给出每个模块中的具体实例。四、仓库源码中的映射实证七个模块的实战案例4.1 FILETIMEDWORD 高低位拼出 64 位时间戳internal/common/common_windows.gotype FILETIME struct { DwLowDateTime uint32 DwHighDateTime uint32 }FILETIME由两个DWORD组成实际代表一个 64 位计数自 1601-01-01 起 100 纳秒数。在 cpu_windows.go 中systemTimes()调用GetSystemTimes后需要手工把两个 32 位拼成 64 位idle : uint64(lpIdleTime.DwHighDateTime)32 | uint64(lpIdleTime.DwLowDateTime) user : uint64(lpUserTime.DwHighDateTime)32 | uint64(lpUserTime.DwLowDateTime) kernel : uint64(lpKernelTime.DwHighDateTime)32 | uint64(lpKernelTime.DwLowDateTime)这是备忘录类型→Go 代码最直接的翻译范例DWORD 对应uint32高位左移 32 位拼接。4.2 MEMORYSTATUSEXDWORD ULONGLONG 混合布局mem/mem_windows.gotype memoryStatusEx struct { cbSize uint32 // DWORD dwMemoryLoad uint32 // DWORD ullTotalPhys uint64 // ULONGLONG/DWORDLONG ullAvailPhys uint64 ullTotalPageFile uint64 ullAvailPageFile uint64 ullTotalVirtual uint64 ullAvailVirtual uint64 ullAvailExtendedVirtual uint64 }注意第 42 行memInfo.cbSize uint32(unsafe.Sizeof(memInfo))Windows 结构体惯例要求调用前先把结构体自身大小写进第一个DWORD字段Go 侧用unsafe.Sizeof精确计算这要求 Go 结构体与 C 结构体的内存布局必须逐字节一致。该结构体在 mem/ex_windows.go 的ExWindows.VirtualMemory()中也被复用。4.3 OSVERSIONINFOEXWDWORD WORD 组合host/host_windows.gotype osVersionInfoExW struct { dwOSVersionInfoSize uint32 // DWORD dwMajorVersion uint32 // DWORD dwMinorVersion uint32 // DWORD dwBuildNumber uint32 // DWORD dwPlatformId uint32 // DWORD szCSDVersion [128]uint16 // WCHAR 数组 wServicePackMajor uint16 // WORD wServicePackMinor uint16 // WORD wSuiteMask uint16 // WORD wProductType uint8 wReserved uint8 }这里dw前缀字段全是uint32DWORDw前缀字段全是uint16WORDsz开头的宽字符串用uint16数组UTF-16即 WCHAR。该结构体通过procRtlGetVersion.Call传给 ntdll用于绕过GetVersionEx在 Windows 8.1 上的说谎问题见 host_windows.go 的注释。4.4 SYSTEM_INFODWORD_PTR 的典型场景host/host_windows.gotype systemInfo struct { wProcessorArchitecture uint16 wReserved uint16 dwPageSize uint32 // DWORD lpMinimumApplicationAddress uintptr // LPVOID指针 lpMaximumApplicationAddress uintptr // LPVOID指针 dwActiveProcessorMask uintptr // DWORD_PTR指针精度 dwNumberOfProcessors uint32 // DWORD dwProcessorType uint32 dwAllocationGranularity uint32 wProcessorLevel uint16 wProcessorRevision uint16 }dwActiveProcessorMask是备忘录中DWORD_PTRunsigned long type for pointer precision的直接对应——它是一个位掩码每一位代表一个逻辑处理器位宽必须与指针一致Go 里只能写uintptr。同样的结构体在 mem/mem_windows.go 和 process/process_windows.go 中重复出现可见这是跨模块的公共基础类型。4.5 SYSTEM_PROCESSOR_PERFORMANCE_INFORMATIONLONGLONG 的实战cpu/cpu_windows.gotype win32_SystemProcessorPerformanceInformation struct { IdleTime int64 // LONGLONG KernelTime int64 UserTime int64 DpcTime int64 InterruptTime int64 InterruptCount uint64 // ULONG needs to be uint64 }注释里 ULONG needs to be uint64 非常值得玩味C 侧ULONG在 Windows 上固定是 32 位但这里用uint64——在NtQuerySystemInformation的实际返回布局中该字段按 64 位对齐/占用。这提醒我们结构体布局翻译有时不能只看类型定义还要看内核实际返回的内存布局对齐、填充。CPU 时间以 100 纳秒为单位换算秒数时除以ClocksPerSec 10000000.0cpu/cpu_windows.go。4.6 PROCESS_BASIC_INFORMATIONINT_PTR / LONG_PTR 的 32/64 位双版本process/process_windows.gotype processBasicInformation32 struct { Reserved1 uint32 PebBaseAddress uint32 // 32 位进程指针是 4 字节 ... UniqueProcessId uint32 ... } type processBasicInformation64 struct { Reserved1 uint64 PebBaseAddress uint64 // 64 位进程指针是 8 字节 ... UniqueProcessId uint64 ... }PROCESS_BASIC_INFORMATION中的PebBaseAddress和UniqueProcessId在 C 定义中是PVOID/ULONG_PTR——即备忘录中的指针精度类型。由于 gopsutil 需要在 32 位与 64 位系统上正确处理 32/64 位进程仓库维护了 32 与 64 两套结构体定义相关调用链在 process_windows_32bit.go 与 process_windows_64bit.go并通过NtQueryInformationProcess/ PEB 两条路径读取见 process_windows_test.go。这正是_WIN64 __int64 else int这类条件定义的现实写照。4.7 DISK_PERFORMANCE 与 MIB_IF_ROW2对齐与填充的教科书disk/disk_windows.gotype diskPerformance struct { BytesRead int64 // LONGLONG ... ReadCount uint32 // DWORD ... StorageManagerName [8]uint16 // WCHAR 数组 alignmentPadding uint32 // necessary for 32bit support }注释明确指出alignmentPadding是necessary for 32bit supportGo 的uint64在 32 位平台上只有 4 字节对齐而 Windows 的ULONG64按 8 字节对齐因此需要手工补一个uint32填充字段把后续字段推到正确的对齐边界。同样的技巧也出现在 net/net_windows.gopad0for64_4for32 (8 - unsafe.Alignof(uint64(0))) % 8MIB_IF_ROW2中InterfaceLuiduint64之后紧跟 32 位字段时仓库用unsafe.Alignof动态计算 32 位平台所需的填充量并注释Windows aligns ULONG64 to 8 bytes. Go gives uint64 only 4-byte alignment on 32-bit。这是对备忘录类型信息最深入的运用不仅要知道类型位宽还要知道其在结构体中的对齐规则。4.8 WORD 与宽字符串WCHAR 数组无处不在备忘录中的WORD16 位无符号整数在 Windows 编程中最常见的形态其实是UTF-16 宽字符串WCHAR。仓库中所有 Windows API 调用都通过windows.StringToUTF16Ptr把 Go 字符串转成uint16指针例如 disk/disk_windows.go 的GetDiskFreeSpaceExW、host/host_windows.go 的RegOpenKeyEx注册表路径。宽字符串数组字段统一用[N]uint16声明如szCSDVersion [128]uint16、StorageManagerName [8]uint16。五、PDH 性能计数器与 WMI类型备忘录之外的读取通道除了直接翻译 C 结构体internal/common/common_windows.go 还定义了 PDHPerformance Data Helper格式值结构体type PDH_FMT_COUNTERVALUE_DOUBLE struct { CStatus uint32 // DWORD DoubleValue float64 } type PDH_FMT_COUNTERVALUE_LARGE struct { CStatus uint32 LargeValue int64 // LONGLONG } type PDH_FMT_COUNTERVALUE_LONG struct { CStatus uint32 LongValue int32 padding [4]byte }PDH_FMT_COUNTERVALUE_LONG中的padding [4]byte同样是显式填充保证LongValue的对齐与 C 侧一致。这些结构体服务于 PDH 计数器查询PdhOpenQuery/PdhAddEnglishCounterW/PdhGetFormattedCounterValue见 common_windows.go例如 mem/mem_windows.go 的SwapMemory就用\Paging File(_Total)\% Usage计数器获取交换内存使用率。六、实战要点总结为 Windows API 编写 Go 结构体布局综合备忘录与仓库实践翻译 Windows 类型时的经验法则如下先查备忘录定位宽固定位宽类型DWORD→uint32、LONGLONG→int64、WORD→uint16直接映射*_PTR与SIZE_T/SSIZE_T一律用uintptr/int因为它们随_WIN64切换。留意结构体首字段多数 Windows 结构体MEMORYSTATUSEX、PERFORMANCE_INFORMATION、OSVERSIONINFOEXW首个字段是cbSize/dwOSVersionInfoSizeDWORD调用前必须用unsafe.Sizeof回填见 mem/mem_windows.go。不要忽略对齐与填充32 位平台下 Go 的uint64只有 4 字节对齐与 Windows 的 8 字节对齐不一致时需手工填充见 disk/disk_windows.go 与 net/net_windows.go个别内核结构体返回布局与头文件定义有出入如InterruptCount用uint64需以实际行为为准cpu/cpu_windows.go。跨进程/跨位宽场景要定义多套结构体32 位进程与 64 位进程的指针精度不同需像processBasicInformation32/64那样分别定义process/process_windows.go。缓冲区分配采用先查询、后分配、再查询模式Windows API 常用ERROR_INSUFFICIENT_BUFFER通知调用方缓冲区过小gopsutil 的getSystemLogicalProcessorInformationExcpu/cpu_windows.go与QueryStatusWithContextwinservices/winservices.go都先传空指针拿到所需字节数再分配并二次调用必要时用CallWithExpandingBuffercommon_windows.go循环扩容。七、结语windows_memo.rst 虽是一份极简的速查备忘但它浓缩了 Windows API 编程中最基础也最关键的位宽知识。在 gopsutil 中这份清单被落地为cpu、mem、host、process、net、disk、winservices各模块数以百计的结构体定义——从FILETIME的高低 DWORD 拼接到DWORD_PTR亲和力掩码再到 32 位平台的对齐填充处处可见这张类型表的影子。掌握这张表及其 Go 映射就等于拿到了阅读和理解 gopsutil Windows 底层实现的钥匙反过来如果你要为自己的 Go 程序接入 Windows 原生 API仓库中这些经过验证的结构体布局也是可以直接参考的最佳实践样板。赞分享开发工具运维【免费下载链接】gopsutilpsutil for golang项目地址https://gitcode.com/gh_mirrors/go/gopsutil点击查看免费下载相关推荐3分钟跑起开源思维导图从空白画布到导出成图3分钟跑起开源思维导图从空白画布到导出成图 每次做复盘都要用表格拼模块关系分享时截图还总糊成一片。开源思维导图 SimpleMindMap 在本地画出结构前端UI组件QuantConnect Lean算法交易引擎5大核心模块深度解析与实战指南QuantConnect Lean算法交易引擎5大核心模块深度解析与实战指南 QuantConnect Lean算法交易引擎是一个功能完备的量化投资开发平台金融科技后端Remotion 模板市场完整指南发现、选择并使用社区视频模板Remotion 模板市场完整指南发现、选择并使用社区视频模板 Remotion 是一款基于 React 的可编程视频创建工具其模板体系是上手最快的起点。R音视频AI 应用前端上一篇DLSS Swapper终极教程3分钟掌握游戏性能优化神器下一篇Rhino.Inside.Revit终极指南5步掌握BIM参数化设计一体化创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考