Windows下用GetAdaptersAddresses获取适配器列表和MAC最稳定,需链接Iphlpapi.lib、两次调用(先传NULL获缓冲区大小再重试)、传AF_UNSPEC、遍历链表过滤OperStatusUp且PhysicalAddressLength==6的适配器,从PhysicalAddress[0..5]提取MAC。

Windows下用GetAdaptersAddresses获取适配器列表和MAC
在Windows上,GetAdaptersAddresses 是最稳定、推荐的方式,替代已废弃的 GetAdaptersInfo。它能一次性拿到 IPv4/IPv6 地址、接口索引、描述、MAC 地址(PhysicalAddress 字段)等完整信息。
关键点:必须链接 Iphlpapi.lib,调用前用 GetAdaptersAddresses 传 0 获取所需缓冲区大小,再分配内存重试;AF_UNSPEC 表示获取所有协议栈信息;GAA_FLAG_INCLUDE_PREFIX 可选,用于获取子网前缀(一般不需要)。
-
PhysicalAddressLength为 6 表示以太网,此时PhysicalAddress[0..5]就是 MAC 字节序列 - 过滤掉
OperStatus != IfOperStatusUp或IfType == IF_TYPE_SOFTWARE_LOOPBACK的条目,避免返回无效或回环适配器 - 注意
FirstUnicastAddress链表才是 IPv4/IPv6 地址所在位置,不是IpAddressList(那是旧 API 的字段)
Linux下读取 /sys/class/net/ 获取 MAC
Linux 没有统一系统调用,最轻量可靠的方式是遍历 /sys/class/net/ 目录,对每个子目录读取 address 文件(如 /sys/class/net/eth0/address),内容即小写十六进制 MAC,如 00:1a:2b:3c:4d:5e。
需跳过虚拟设备(如 lo、docker0、veth*)和无 MAC 的设备(如 ip6tnl0)——判断依据是:address 文件存在且内容为 17 字符(含冒号)、非全零、且对应目录下 operstate 为 up。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
立即学习“C++免费学习笔记(深入)”;
- 不要依赖
ifconfig或ip link show的输出解析,它们受 locale 和格式变动影响大 -
net/if.h+ioctl(SIOCGIFHWADDR)虽可行,但需逐个打开 socket、构造ifreq,出错处理繁琐,且某些虚拟接口可能返回ENODEV或EINVAL -
/sys/class/net/*/device存在表示物理设备,但不是绝对标准;更稳妥的是结合dev_id(为空)和type(值为 1 表示以太网)
跨平台封装时要注意的陷阱
MAC 地址本身没有“格式”概念,它是 6 字节二进制数据;不同平台返回顺序一致(网络字节序无意义,MAC 是扁平地址),但展示时 Windows 常用大写分号,Linux 默认小写冒号。别在代码里硬编码分隔符或大小写转换逻辑。
- Windows 的
PhysicalAddress是 raw bytes,长度由PhysicalAddressLength决定;某些设备(如 InfiniBand)可能是 20 字节,不能假设一定是 6 - Linux 下
/sys/class/net/*/address可能不存在(如某些 ppp 接口),读取失败应跳过而非报错 - 多线程环境下,
GetAdaptersAddresses返回的内存块需由调用方free();Linux 方式则无内存管理负担 - 容器环境(Docker/K8s)中,宿主机看到的
eth0在容器内可能是eth0或ens3,且 MAC 可能被覆盖(如使用--mac-address),需明确采集上下文
MacOS 上用 getifaddrs + AF_LINK 提取 MAC
macOS 不支持 GetAdaptersAddresses,也不推荐读 /sys(不存在)。正确方式是调用 getifaddrs,遍历链表,对每个 ifa_addr->sa_family == AF_LINK 的节点,强转为 struct sockaddr_dl *,从中提取 sdl_data + sdl_nlen 开始的 sdl_alen 字节 —— 这就是 MAC。
getifaddrs 返回结构包含所有接口(含 lo),需检查 ifa_flags & IFF_UP 且 sdl_type == IFT_ETHER(过滤掉隧道、PPP 等)。
-
struct sockaddr_dl的布局在不同 macOS 版本略有差异,务必用sdl_alen判断实际长度,不要硬写 6 - 注意
getifaddrs分配的内存必须用freeifaddrs释放,否则内存泄漏 - 某些虚拟网卡(如 VMware Fusion 的
vmnet)sdl_type可能为IFT_OTHER,但sdl_alen == 6,可酌情保留
operstate,macOS 看 IFF_UP。如果业务需要“能通信的物理网卡”,还得额外 ping 或 connect 测试连通性,仅靠系统接口状态不够可靠。

















