windows下最稳定获取mac地址的方式是调用getadaptersaddresses,需链接iphlpapi.lib、两次调用处理缓冲区、遍历链表筛选operstatusup且physicaladdresslength==6的适配器,并格式化输出。

Windows下用GetAdaptersAddresses获取MAC地址
Windows平台最稳定的方式是调用GetAdaptersAddresses,它比过时的GetAdaptersInfo支持IPv6、返回更完整,并能跳过虚拟网卡和未连接设备。
关键点:
- 需链接
Iphlpapi.lib,头文件包含#include <iphlpapi.h></iphlpapi.h> - 调用前先传
NULL获取所需缓冲区大小,再分配内存重试——否则大概率返回ERROR_BUFFER_OVERFLOW - 遍历
IP_ADAPTER_ADDRESSES链表时,检查OperStatus == IfOperStatusUp且PhysicalAddressLength == 6才认为是有效的以太网/MAC地址 - MAC地址存于
PhysicalAddress字段,是字节数组,需手动格式化为XX-XX-XX-XX-XX-XX形式
示例片段(省略错误处理):
ULONG size = 0;
GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER, nullptr, nullptr, &size);
auto buf = std::vector<BYTE>(size);
PIP_ADAPTER_ADDRESSES addr = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(buf.data());
GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER, nullptr, addr, &size);
for (auto p = addr; p; p = p->Next) {
if (p->OperStatus == IfOperStatusUp && p->PhysicalAddressLength == 6) {
printf("%02X-%02X-%02X-%02X-%02X-%02X\n",
p->PhysicalAddress[0], p->PhysicalAddress[1], p->PhysicalAddress[2],
p->PhysicalAddress[3], p->PhysicalAddress[4], p->PhysicalAddress[5]);
}
}
Linux下读取/sys/class/net/*/address
Linux不提供统一API,最轻量可靠的做法是遍历/sys/class/net/下的每个子目录,读取其中的address文件。
立即学习“C++免费学习笔记(深入)”;
注意项:
- 跳过
lo、docker0、veth*等非物理接口——可结合device/driver是否存在判断是否挂载真实驱动 -
address文件内容是小写十六进制加冒号分隔(如00:1a:2b:3c:4d:5e),末尾带换行符,读取后需trim - 某些容器环境或旧内核可能没有
address文件,应备选尝试/proc/net/dev中解析接口名后fallback - 权限足够即可,无需root;但若程序以drop privileges方式运行,需确保对
/sys/class/net/有读权限
macOS用getifaddrs + ioctl(SIOCGIFHWADDR)
macOS不能直接从getifaddrs拿到MAC,必须对每个接口调用ioctl配合SIOCGIFHWADDR——这是最容易漏掉的步骤,仅靠ifa_addr会返回AF_LINK但数据不可用。
实操要点:
- 先用
getifaddrs(&ifaddr)获取接口列表,过滤ifa_addr->sa_family == AF_LINK - 对每个匹配接口,
socket(AF_INET, SOCK_DGRAM, 0)创建临时fd,再ioctl(fd, SIOCGIFHWADDR, &ifr) -
ifr.ifr_hwaddr.sa_data前6字节即MAC,注意字节序无须转换,直接复制即可 - 别忘了
close(fd)和freeifaddrs(ifaddr),否则资源泄漏
跨平台封装要注意的硬伤
不同系统返回的“有效MAC”定义不一致:Windows可能返回Hyper-V虚拟交换机的MAC,Linux可能暴露veth peer,macOS甚至会把FireWire接口也当网络适配器。单纯拼长度或字段存在风险。
真正健壮的判断逻辑应组合多个条件:
- 接口状态为UP(非NOARP/DOWN)
- 硬件类型为
ARPHRD_ETHER(Linux/macOS可通过ifr.ifr_type或sa_data[0]推断) - 排除名称含
virbr、vnet、docker、br-等已知虚拟前缀 - 优先返回第一个满足条件的非回环接口,而非固定索引第0个
另外,GetAdaptersAddresses在Windows Server 2003上不可用,getifaddrs在部分嵌入式glibc中被阉割——如果目标环境不确定,得准备备用路径,比如Windows fallback到Netbios或WMI,Linux fallback到ip link show解析stdout。










