跨平台获取网卡ip应优先使用getifaddrs(linux/macos)或getadaptersaddresses(windows),统一抽象为interfaceinfo结构,过滤时依据iff_loopback标志及接口名称特征,避免硬编码ip段。

用 getifaddrs 获取所有接口 IP(Linux/macOS 主流方案)
跨平台获取网卡 IP,Linux 和 macOS 优先走 getifaddrs —— 它能一次拿到 IPv4/IPv6 地址、掩码、广播地址、标志位(如是否 up、是否 loopback),且无需 root 权限。
常见错误是直接遍历 ifconf + ioctl(SIOCGIFADDR):它只返回主 IP,不支持别名地址(如 eth0:0),也无法区分 IPv6 link-local 和 global 地址。
实操要点:
-
getifaddrs返回链表,需用freeifaddrs释放,漏掉会内存泄漏 - 过滤条件必须检查
ifa_addr->sa_family,跳过AF_PACKET、AF_UNSPEC等非 IP 类型 - IPv6 地址需用
inet_ntop(AF_INET6, &((struct sockaddr_in6*)addr)->sin6_addr, ...)转字符串,不能用inet_ntoa - 注意
ifa_flags中的IFF_UP和IFF_RUNNING,仅IFF_UP不代表能通外网(比如网线没插)
Windows 上用 GetAdaptersAddresses 替代 getifaddrs
Windows 没有 getifaddrs,等价方案是 GetAdaptersAddresses。它返回的是结构体数组(不是链表),但字段更细:含 DNS 后缀、跃点数、连接状态(OperStatus)、甚至 DHCP 服务器地址。
容易踩的坑:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 必须传
AF_UNSPEC才能同时拿到 IPv4 和 IPv6;传AF_INET会丢掉 IPv6 地址 - 返回缓冲区可能不足,首次调用要先用
NULL+size = 0获取所需大小,再 malloc 分配后重试 -
FirstUnicastAddress链表里每个节点含Address.lpSockAddr,但 IPv6 地址可能带 scope id(如%eth0),解析时需用getnameinfo或手动截断 - 某些虚拟网卡(如 Hyper-V、DockerNAT)会返回
OperStatus == IfOperStatusDown却仍有有效 IP,不能仅靠状态过滤
跨平台封装的关键:抽象出统一的数据结构
不要在业务逻辑里写 #ifdef _WIN32 判断分支——把差异收进一个薄层,对外暴露干净接口,比如:
struct InterfaceInfo {
std::string name; // "eth0", "en0", "Ethernet"
std::string addr; // "192.168.1.10", "::1"
int family; // AF_INET / AF_INET6
bool is_up; // IFF_UP && (IFF_RUNNING or OperStatusUp)
};
std::vector<interfaceinfo> get_all_ips();
</interfaceinfo>
这样上层代码完全不用关心平台细节。注意 name 字段在 Windows 上对应 AdapterName(如 {xxxx-xxxx}),建议额外提供 FriendlyName(如 "Wi-Fi")供日志和调试用,但业务逻辑应以稳定标识(如 MAC 或索引)为准,避免依赖用户可改的名称。
忽略 localhost 和 Docker/virtual 接口的判断逻辑
真实场景中,你通常不需要 127.0.0.1、::1、172.17.0.1(docker0)、192.168.99.1(VirtualBox)这些地址。但“过滤”不能只靠 IP 段硬匹配:
- IPv6 的
::1是 loopback,但fe80::/10是 link-local,不一定该过滤(比如本地服务发现就靠它) - Docker 桥接网段不固定(
172.17.0.0/16是默认,但用户可改),更可靠的方式是查ifa_flags & IFF_LOOPBACK或 Windows 的Ipv6IfIndex == 1(loopback 接口索引恒为 1) - 虚拟网卡常带特定描述符:Linux 下看
ifa_name是否含"docker"、"veth"、"br-";Windows 下看AdapterName是否含"vEthernet"或Description含"Hyper-V"
最稳妥的做法是提供白名单机制(如允许用户配置保留的接口名),而不是试图全自动识别“有用”接口。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










