Windows上获取MAC地址唯一推荐方式是GetAdaptersAddresses:需先以AF_UNSPEC和空缓冲区调用获所需大小,再分配内存重试;遍历时仅当OperStatus为Up且PhysicalAddressLength为6时才有效,并须用FreeMibTable释放内存。

GetAdaptersAddresses 是 Windows 上唯一推荐的现代方式,旧 API 如 GetAdaptersInfo 和 GetNetworkParams 在 Server 2012+、WSL2、Hyper-V 虚拟网卡等环境中已不可靠,直接调用大概率返回空、全零或漏掉接口。
为什么第一次调用 GetAdaptersAddresses 总是 ERROR_BUFFER_OVERFLOW
这不是错误,而是 Windows 的强制设计流程:它拒绝在你没准备好缓冲区时填数据。
- 第一次必须传
nullptr作pAdapterAddresses,并传一个初始化为0的ULONG*给SizePointer,函数会把所需字节数写进去 - 立刻检查返回值是否为
ERROR_BUFFER_OVERFLOW—— 只有这个值才表示“请重试”,其他非NO_ERROR值才是真失败 - 用拿到的大小分配内存(推荐
std::vector<byte></byte>或malloc),第二次再传进去;千万别用栈数组,大网卡列表可能吃掉几 KB 甚至上万字节 - 第二次调用后,必须检查返回值是否为
NO_ERROR,否则结构体链表无效
AF_UNSPEC 不是可选项,是必填参数
传 AF_INET 会过滤掉纯 IPv6 接口(比如 WSL2 的 vEthernet、Docker 的 docker0),传 AF_INET6 同样漏 IPv4 接口。这些虚拟适配器虽然不参与某类协议栈,但物理地址依然存在。
- 固定用
AF_UNSPEC,这是唯一能覆盖所有类型网卡的方式 - 别依赖
IfType判断是否“有 MAC”——有些 USB 网卡报告IF_TYPE_ETHERNET_CSMACD,但PhysicalAddressLength == 0;有些蓝牙 PAN 报IF_TYPE_IEEE802154却有 8 字节地址 - 真正有效的判断条件只有两个:
OperStatus == IfOperStatusUp(接口已启用)且PhysicalAddressLength == 6(标准以太网长度)
遍历链表时最常崩的三个点
返回的是单向链表,不是数组,Next 指针随时可能为 nullptr 或指向截断结构体。
在 Windows 11 上"直接发声"的 TTS(从 WSL2/TUI 调用 powershell.exe + System.Speech)。适用于用户说"说出来/读出来/语音播报/用TTS",或反馈"没声音/tts 生成的 mp3 是空的/播不出来",以及需要中文语音但 OpenClaw 内置 tts 不可用时。
- 每次取
pAdapter = pAdapter->Next前,必须加if (!pAdapter) break;,否则访问空指针崩溃 - 每个节点要校验
pAdapter->Length >= sizeof(IP_ADAPTER_ADDRESSES),防止缓冲区不足导致结构体被截断 -
PhysicalAddress是裸字节数组,不是字符串,不能printf("%s", ...);格式化时必须按PhysicalAddressLength循环,用%02X输出,每字节后加-(末尾去掉)
链接与清理容易被忽略的细节
看似简单,但漏掉就编译不过或内存泄漏。
立即学习“C++免费学习笔记(深入)”;
- 头文件必须包含
#include <iphlpapi.h></iphlpapi.h>,链接库必须加-liphlpapi(MSVC 下用#pragma comment(lib, "iphlpapi.lib")) - 分配的缓冲区内存必须用
FreeMibTable释放,不能用free或delete—— Windows 文档明确要求这点,否则可能引发未定义行为 - 如果程序运行在低权限上下文(如受限服务、沙箱进程),部分 Hyper-V 或 WSL2 虚拟交换机接口可能根本不会出现在结果里,这不是 bug,是系统策略限制
ERROR_BUFFER_OVERFLOW 就会变成段错误或静默丢数据。

















