Windows下最可靠方式是调用GetAdaptersAddresses,需传AF_UNSPEC、两次调用处理缓冲区、遍历链表提取IPv4/IPv6、MAC、OperStatus等字段,并过滤未启用接口。

用 GetAdaptersAddresses 获取 Windows 全部适配器信息
Windows 下最可靠的方式是调用 GetAdaptersAddresses,它能返回 IPv4/IPv6 地址、MAC、状态、描述等完整字段,且兼容 WinXP 及以上系统。别用已废弃的 GetAdaptersInfo,它不支持 IPv6 且字段缺失严重。
关键点:
-
GetAdaptersAddresses需要传入AF_UNSPEC才能同时获取 IPv4 和 IPv6 信息;只传AF_INET会漏掉 IPv6 地址和某些虚拟适配器 - 第一次调用会返回
ERROR_BUFFER_OVERFLOW,必须根据输出的SizePointer分配足够内存再重试,直接 malloc 固定大小(比如 8KB)大概率失败 - 返回结构体链表中,每个
IP_ADAPTER_ADDRESSES的FirstUnicastAddress字段指向该适配器所有 IP 地址链表,需遍历读取,不是只看Ipv4Address字段 - 注意检查
OperStatus字段判断是否启用(IfOperStatusUp),很多“禁用”或“未连接”的适配器仍会出现在列表里
Linux 下用 getifaddrs 读取接口地址信息
getifaddrs 是 POSIX 标准接口,Linux/macOS 都支持,但只返回地址和接口名,不提供 MAC、描述、状态等元数据——想拿到完整信息得额外调 ioctl(SIOCGIFHWADDR) 和 SIOCGIFFLAGS。
常见陷阱:
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
-
getifaddrs返回的ifa_addr可能为nullptr(比如 lo 接口没配置 IPv4),访问前必须判空,否则崩溃 - IPv6 地址可能带 scope_id,
sockaddr_in6中的sin6_scope_id在打印时需显式过滤,否则地址显示异常(如fe80::1%lo) - 不要依赖
ifa_flags & IFF_UP判断是否可用:有些接口 flag 是 UP,但实际无链路(如 DHCP 未获地址),需结合ifa_addr是否有效综合判断
C++ 封装跨平台适配器枚举的注意事项
跨平台封装时,别试图抽象出统一结构体——Windows 的 IP_ADAPTER_ADDRESSES 和 Linux 的 ifaddrs 字段语义差异太大,硬合并会导致字段含义模糊或丢失精度。
更实用的做法:
- 定义一个最小公共结构体(含接口名、IPv4、IPv6、MAC、是否启用),其余字段按平台分别暴露原生指针(如
void* windows_adapter/struct ifaddrs* linux_ifaddr) - MAC 地址在 Windows 中是
PhysicalAddress数组,在 Linux 中需ioctl(SIOCGIFHWADDR)提取,二者长度都是 6 字节,但 Windows 有PhysicalAddressLength字段防越界,Linux 必须手动校验sa_data长度 - 接口名称:Windows 中
AdapterName是 GUID 字符串(如{B2F3C...}),可读性差,建议优先用Description;Linux 中ifa_name直接可用,但像docker0、vethxxx这类虚拟接口需根据业务需求决定是否过滤
容易被忽略的权限与兼容性问题
普通用户进程在多数场景下能调用 GetAdaptersAddresses 或 getifaddrs,但以下情况会失败:
- Windows 上若启用了“网络访问:不允许匿名 SID/名称映射”,非管理员调用
GetAdaptersAddresses可能返回ERROR_ACCESS_DENIED(尤其在域环境) - Linux 容器中,如果网络命名空间被隔离(如
--network=none),getifaddrs可能只返回lo,且ioctl查询 MAC 会失败,需提前检查/proc/sys/net/core/somaxconn等路径是否存在来判断环境完整性 - macOS 上
getifaddrs不返回虚拟网卡(如 VMware Fusion 的vmnet),必须用SystemConfiguration.framework的SCNetworkInterfaceCopyAll替代,且需链接-framework SystemConfiguration
真实环境中,一个接口可能有多个 IPv4 地址、多个 IPv6 地址、多个作用域(link-local/global)、甚至临时地址(RFC 4941),光靠“获取全部适配器”远远不够——关键是要明确你真正需要的是活跃地址、默认路由出口、还是所有配置痕迹。

















