gopsutil 的 Windows 数据类型备忘录:DWORD、SIZE_T 等基础类型的完整释义与 Go 映射实践
开发工具运维【免费下载链接】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),仅供参考

相关新闻

Node.js压缩包安装全指南:从解压到环境变量配置与问题排查

Node.js压缩包安装全指南:从解压到环境变量配置与问题排查

很多刚接触 Node.js 的朋友,第一反应都是去官网下载那个 .msi 或 .pkg 的安装包,一路 Next 到底,装完收工。这种做法本身没什么问题,但我个人折腾这么多年环境、帮同事处理过各种灵异报错之后,越来越倾向于推荐另一种方…

2026/10/14 2:57:30 阅读更多 →
VLP平台与重组蛋白:新一代生物技术工具

VLP平台与重组蛋白:新一代生物技术工具

VLP平台的基本概念与技术原理病毒样颗粒(VLP)平台是一种新兴的生物技术工具,它利用重组蛋白自组装形成在结构上模拟天然病毒颗粒的空心颗粒。这些颗粒不含病毒遗传物质,因此不具备复制和感染能力,但保留了病毒的免疫原…

2026/10/14 2:56:30 阅读更多 →
情感表达的艺术:正经话如何撩动人心

情感表达的艺术:正经话如何撩动人心

1. 情感表达的艺术:如何用正经话撩动人心"句句正经,句句撩到心巴"这个标题让我想起十年前刚做情感博主时的一个发现:最动人的情话往往藏在最日常的对话里。当时有位读者留言说,她男朋友在讨论周末买菜时随口说了句"…

2026/10/14 2:56:30 阅读更多 →

最新新闻

一张图微调YOLOv11:自然栖息地鸟类检测的流程与扩充

一张图微调YOLOv11:自然栖息地鸟类检测的流程与扩充

简介:面向 YOLOv11 模型验证需求,这份精简版鸟类目标检测数据集包含一张真实野外鸟类图像及配套标准标注,可用于快速原型验证、轻量级部署测试与小样本检测基线建立。压缩包共五个文件,包含三张 JPG 图像、一个数据配置文件与一个…

2026/10/14 3:39:38 阅读更多 →
ASP.NET + SQLServer葡萄酒商城源码:从数据库还原到下单事务全攻略

ASP.NET + SQLServer葡萄酒商城源码:从数据库还原到下单事务全攻略

简介:一套基于ASP.NET与SQL Server的葡萄酒网上商城销售系统,面向ASP.NET WebForm学习者、毕业设计学生以及需要搭建在线商城教学演示的开发者。系统围绕普通会员、商户会员和管理员三类角色展开,覆盖商品管理、购物车、订单处理、发货、商户…

2026/10/14 3:39:38 阅读更多 →
LangChain项目代码拆解:Chain、Agent、Memory与Retrieval四大核心组件实战指南

LangChain项目代码拆解:Chain、Agent、Memory与Retrieval四大核心组件实战指南

简介:这是一份LangChain入门与实践的项目代码包,面向正在学习大模型应用开发的Python开发者,旨在帮助读者快速理解LangChain的模块化设计与核心用法。包内共3个文件,包含一个HTML格式的入门讲解页、一个项目运行配置文件以及一个版…

2026/10/14 3:39:38 阅读更多 →
C++学习日记 Day21:C++11(下)lambda表达式和function包装器

C++学习日记 Day21:C++11(下)lambda表达式和function包装器

## 今天学了什么今天学习C11的lambda表达式和function包装器。## 可调用对象概念:在C中有一类对象可像函数一样调用;分类:①函数指针using prt void(*)(int, string); prt f1 fun; f1(1, "函数指针");②仿函数 --有 operator&am…

2026/10/14 3:39:38 阅读更多 →
一人公司AI工作流:6步实现内容生产去体力化

一人公司AI工作流:6步实现内容生产去体力化

1. 一人公司的内容困局与破局思路一个人做内容,最怕的不是没灵感,而是灵感来了却卡在“执行”上。写一篇长文要三小时,做一张配图要半小时,剪一条短视频要一整个下午,排版发布又要来回切换四五个平台。一天下来&#x…

2026/10/14 3:39:38 阅读更多 →
8765平台前后摄DVDD电压不一致排查与修复指南

8765平台前后摄DVDD电压不一致排查与修复指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 3:38:38 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →