Linux下最可靠方式是用getifaddrs遍历链表,筛选sa_family==AF_PACKET、IFF_UP且非LOOPBACK的接口,从sa_data+2取6字节MAC;Windows必须用GetAdaptersAddresses,两次调用获取缓冲区,检查IfType==IF_TYPE_ETHERNET_CSMACD且OperStatus==IfOperStatusUp,从PhysicalAddress字段提取。

Linux下用getifaddrs获取MAC地址最可靠
直接读/sys/class/net/路径虽然快,但依赖内核接口稳定性,且对虚拟网卡(如veth、docker0)可能返回空或错误值。用getifaddrs是POSIX标准做法,能统一处理物理网卡、bond、bridge等各类接口。
关键点:
-
getifaddrs返回链表,需遍历每个ifaddrs*节点,检查ifa_addr->sa_family == AF_PACKET - MAC地址在
ifa_addr->sa_data偏移2字节处,共6字节;不要直接取sa_data[0]开始——那是2字节协议类型字段 - 跳过
lo(回环)、docker0、virbr0等非物理上行接口,建议按ifa_flags & IFF_UP和!(ifa_flags & IFF_LOOPBACK)双重过滤 - 示例片段:
struct ifaddrs *ifaddr, *ifa; if (getifaddrs(&ifaddr) == 0) { for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) { if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_PACKET && ifa->ifa_flags & IFF_UP && !(ifa->ifa_flags & IFF_LOOPBACK)) { unsigned char *mac = (unsigned char*)ifa->ifa_addr->sa_data + 2; // mac[0] ~ mac[5] 即为6字节MAC } } }
Windows下必须用GetAdaptersAddresses而非GetAdaptersInfo
GetAdaptersInfo已废弃,不支持IPv6适配器,且对某些NDIS 6驱动(如Hyper-V虚拟交换机)返回ERROR_NO_DATA。必须用GetAdaptersAddresses,它能正确识别IF_TYPE_ETHERNET_CSMACD类网卡。
注意细节:
立即学习“C++免费学习笔记(深入)”;
- 调用前先传
nullptr获取所需缓冲区大小,再分配内存重试——否则极易因buffer overflow导致崩溃 - 遍历
IP_ADAPTER_ADDRESSES*链表时,检查adapter->IfType == IF_TYPE_ETHERNET_CSMACD,并确认adapter->OperStatus == IfOperStatusUp - MAC存于
adapter->PhysicalAddress,长度由adapter->PhysicalAddressLength给出(通常为6,但某些InfiniBand卡可能更长) - 别硬编码取前6字节:有些设备(如某些USB网卡)会把厂商OUI填在前3字节,后3字节为0,实际有效MAC需结合
adapter->Description人工判断
跨平台封装要避开ioctl(SIOCGIFHWADDR)陷阱
很多C++项目试图用ioctl统一处理,但在不同系统上行为差异极大:
- Linux:需
AF_INET套接字+ifr_name指定接口名,但ifr_hwaddr在glibc 2.34+中已被标记为deprecated - macOS:
SIOCGIFHWADDR根本不存在,得用sysctlbyname("net.link.generic.system")配合IFM_TYPE解析 - FreeBSD:需
AF_LINK套接字,且ifr_addr指向sockaddr_dl结构,MAC在sdl_data + sdl_nlen偏移处 - 结论:与其写一堆条件编译,不如分别实现
getifaddrs(Linux/BSD/macOS)和GetAdaptersAddresses(Windows),用宏隔离
获取到的MAC可能不是“本机唯一标识”
这是最容易被忽略的现实问题:
- 多网卡机器会返回多个MAC,选哪个?业务逻辑必须明确策略(例如优先
eth0、或找默认路由所在接口) - 云主机(AWS/Azure)的MAC由Hypervisor分配,重启可能变化;容器内看到的是veth peer的MAC,不是宿主机物理网卡
- 某些安全策略(如Windows组策略“随机化MAC地址”)会导致每次连接Wi-Fi时生成新MAC,
GetAdaptersAddresses返回的只是当前会话值 - 虚拟化环境(VMware/VirtualBox)中,MAC常被配置为固定值,但克隆虚拟机后可能重复,不能直接用作license绑定依据


















