能,GetAdaptersAddresses 是 Windows 唯一推荐的现代方式,需两次调用获取缓冲区大小、遍历链表筛选 PhysicalAddressLength==6 且 OperStatusUp 的适配器,再格式化 PhysicalAddress 字节数组为 XX-XX-XX-XX-XX-XX 形式。

GetAdaptersAddresses 能拿到 MAC 吗?能,但得绕开几个坑
能,GetAdaptersAddresses 是 Windows 上唯一推荐的现代方式,但它返回的 MAC 地址藏在 IP_ADAPTER_ADDRESSES 结构体的 PhysicalAddress 字段里,长度不固定(常见 6 字节,但 InfiniBand、FDDI 等可能更长),且 PhysicalAddressLength 可能为 0 —— 这通常意味着接口没启用、是虚拟环回、或驱动没报告物理层信息。
实操建议:
- 调用前传
AF_UNSPEC和GAA_FLAG_INCLUDE_PREFIX,避免漏掉 IPv6 接口或子网前缀信息 - 必须检查
Adapter->PhysicalAddressLength == 6再格式化输出,否则 memcpy 可能越界 - 跳过
IF_TYPE_SOFTWARE_LOOPBACK(值为 24)和IF_TYPE_TUNNEL(值为 131)这类无真实 MAC 的接口 - 首次调用传
NULL获取所需缓冲区大小,第二次再 malloc + 调用,别硬分配 8KB —— 实际可能只需几百字节,也可能上万(尤其启用了大量容器网络)
为什么 GetNetworkParams 拿不到所有接口的 MAC?
GetNetworkParams 只返回主适配器(通常是第一个启用的有线/无线网卡)的 IP_ADAPTER_INFO,它连 PhysicalAddress 字段都只有 8 字节空间,且不支持 IPv6、隧道、Hyper-V 虚拟交换机等现代接口。Windows Vista 之后微软已明确标记为“legacy”,文档里写着 “not recommended for new applications”。
典型错误现象:GetNetworkParams 返回的 AdapterInfo->Address 全是 00-00-00-00-00-00,或者只返回一个接口,而 ipconfig /all 显示十几个。
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
实操建议:
- 彻底弃用
GetNetworkParams和GetAdapterInfo - 如果必须兼容 XP,才考虑 fallback 到
GetAdaptersInfo(注意:它也只返回 IPv4 接口,且Address字段仍需校验长度) - 不要试图从注册表读
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4d36e972-e325-11ce-bfc1-08002be10318}下的NetworkAddress—— 大部分网卡驱动根本不写这个值
如何安全地把 PhysicalAddress 转成 xx-xx-xx-xx-xx-xx 格式?
不能直接 printf 或 sprintf,因为 PhysicalAddress 是字节数组,不是 C 字符串;也不能假设一定是 6 字节 —— 某些 RDMA 或虚拟网卡会返回 20 字节。
实操建议:
- 先判断
Adapter->PhysicalAddressLength > 0,再循环格式化,每字节用%02X输出,用-分隔 - 用
std::ostringstream或sprintf_s(Windows 安全版)拼接,避免栈溢出 - 示例片段:
char macStr[32] = {0};
if (adapter->PhysicalAddressLength == 6) {
sprintf_s(macStr, sizeof(macStr), "%02X-%02X-%02X-%02X-%02X-%02X",
adapter->PhysicalAddress[0], adapter->PhysicalAddress[1],
adapter->PhysicalAddress[2], adapter->PhysicalAddress[3],
adapter->PhysicalAddress[4], adapter->PhysicalAddress[5]);
}
// macStr 就是标准格式
遇到 ERROR_BUFFER_OVERFLOW 或返回 NULL 怎么办?
这是最常卡住的地方:GetAdaptersAddresses 第一次调用几乎必然失败并返回 ERROR_BUFFER_OVERFLOW,同时把需要的缓冲区大小写入你传入的 SizePointer 参数。很多人忽略这个返回值,直接当成功处理,结果访问野指针。
实操建议:
- 必须检查返回值是否等于
ERROR_BUFFER_OVERFLOW或ERROR_SUCCESS - 若为
ERROR_BUFFER_OVERFLOW,malloc 对应大小(别忘加 1 字节防边界对齐问题),再调用一次 - 若第二次仍失败,检查是否传了
AF_INET6却在纯 IPv4 环境下运行 —— 改用AF_UNSPEC更稳妥 - 某些精简版系统(如 Server Core、IoT Enterprise)可能禁用 NLA 服务,此时函数会返回
ERROR_NOT_SUPPORTED,需降级到 WMI 查询(Win32_NetworkAdapter类)作为 fallback
PhysicalAddressLength。很多代码在开发机上 OK,一到客户环境就崩,八成是没处理好虚拟网卡或未启用接口的地址字段。

















