最可靠方案是linux/macos用getifaddrs、windows用getadaptersaddresses;需过滤af_inet/af_inet6、检查ifa_addr非空及iff_up/operstatusup标志,调用freeifaddrs或正确处理缓冲区,禁用gethostbyname等不可靠方法。

用 getifaddrs 遍历网卡地址最可靠
Linux/macOS 下首选 getifaddrs,它能一次性拿到所有接口的 IPv4/IPv6 地址、掩码、标志位,比反复调用 gethostbyname 或读取 /proc/net/if_inet6 更健壮。Windows 不支持这个函数,得换方案。
关键点:
-
getifaddrs返回的是链表,必须用freeifaddrs释放,否则内存泄漏 - 要过滤掉
AF_INET(IPv4)和AF_INET6(IPv6),跳过AF_PACKET、AF_UNIX等无关类型 - 有些接口(如
lo)可能有多个地址,或含临时 IPv6 地址(IFA_F_TEMPORARY),按需筛选
#include <ifaddrs.h>
#include <netinet>
#include <arpa><p>struct ifaddrs<em> ifa;
if (getifaddrs(&ifa) == 0) {
for (auto p = ifa; p != nullptr; p = p->ifa_next) {
if (p->ifa_addr && (p->ifa_addr->sa_family == AF_INET)) {
auto</em> sa = reinterpret_cast<struct sockaddr_in>(p->ifa_addr);
char ip[INET_ADDRSTRLEN];
if (inet_ntop(AF_INET, &sa->sin_addr, ip, sizeof(ip))) {
printf("%s: %s\n", p->ifa_name, ip);
}
}
}
freeifaddrs(ifa);
}
</struct></p></arpa></netinet></ifaddrs.h>
Windows 上用 GetAdaptersAddresses
Windows 没有 getifaddrs,得用 IP Helper API 的 GetAdaptersAddresses。它返回结构体链表,字段更细(比如能区分 DHCP、隧道、虚拟适配器),但调用稍麻烦。
常见坑:
- 必须传
AF_UNSPEC才能同时拿到 IPv4 和 IPv6;只传AF_INET会漏掉 IPv6 - 第一次调用常返回
ERROR_BUFFER_OVERFLOW,得按提示分配足够大缓冲区再重试 -
FirstUnicastAddress字段才是 IP 地址链表,别误用FirstIpAddress(那是旧版兼容字段,已弃用)
跨平台封装要注意的三件事
如果代码要同时跑在 Linux/macOS/Windows 上,别硬写两套逻辑。用宏或构建系统隔离即可,但注意这些细节:
- Linux/macOS 的
ifa_flags和 Windows 的OperStatus+Flags含义不等价,判断“是否启用”不能简单映射 - IPv6 地址可能带作用域 ID(如
%eth0),打印或使用前要用getnameinfo或手动剥离 - 容器或 WSL 环境下可能看到
docker0、vethxxx、br-开头的接口,是否纳入结果得由业务决定,不是技术问题
别用 gethostname + gethostbyname 查本机 IP
这是新手常见误区:gethostname 只返回主机名,而 gethostbyname 查的是 DNS 解析结果——它可能指向公网 IP、负载均衡 VIP,甚至根本解析失败或返回 127.0.0.1。它完全不反映真实网卡配置。
真正需要“本机所有网卡 IP”时,必须走接口层(getifaddrs / GetAdaptersAddresses),而不是名字服务层。
IPv6 临时地址、DAD 状态未确认的地址、被禁用的接口,都可能出现在结果里。实际使用前最好结合 IFF_UP 和 IFF_RUNNING(Unix)或 OperStatus == IfOperStatusUp(Windows)做过滤。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











