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 接口。这些虚拟适配器虽然不参与某类协议栈,但物理地址依然存在。
通过 SSH 隧道从 Android 设备在互联网上对 Windows PC 实现完整远程控制的设置与使用指南,适用于远程桌面访问、安全 RDP 等。
- 固定用
AF_UNSPEC,这是唯一能覆盖所有类型网卡的方式 - 别依赖
IfType判断是否“有 MAC”——有些 USB 网卡报告IF_TYPE_ETHERNET_CSMACD,但PhysicalAddressLength == 0;有些蓝牙 PAN 报IF_TYPE_IEEE802154却有 8 字节地址 - 真正有效的判断条件只有两个:
OperStatus == IfOperStatusUp(接口已启用)且PhysicalAddressLength == 6(标准以太网长度)
遍历链表时最常崩的三个点
返回的是单向链表,不是数组,Next 指针随时可能为 nullptr 或指向截断结构体。
- 每次取
pAdapter = pAdapter->Next前,必须加if (!pAdapter) break;,否则访问空指针崩溃 - 每个节点要校验
pAdapter->Length >= sizeof(IP_ADAPTER_ADDRESSES),防止缓冲区不足导致结构体被截断 -
PhysicalAddress是裸字节数组,不是字符串,不能printf("%s", ...);格式化时必须按PhysicalAddressLength循环,用%02X输出,每字节后加-(末尾去掉)
链接与清理容易被忽略的细节
看似简单,但漏掉就编译不过或内存泄漏。
- 头文件必须包含
#include <iphlpapi.h></iphlpapi.h>,链接库必须加-liphlpapi(MSVC 下用#pragma comment(lib, "iphlpapi.lib")) - 分配的缓冲区内存必须用
FreeMibTable释放,不能用free或delete—— Windows 文档明确要求这点,否则可能引发未定义行为 - 如果程序运行在低权限上下文(如受限服务、沙箱进程),部分 Hyper-V 或 WSL2 虚拟交换机接口可能根本不会出现在结果里,这不是 bug,是系统策略限制
ERROR_BUFFER_OVERFLOW 就会变成段错误或静默丢数据。大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!










