使用IP_ADAPTER_ADDRESSES时编译报错求助
作为刚接触C++和Windows API的新手,遇到这种编译报错太正常了——MSDN的示例代码是针对Visual Studio(MSVC编译器)写的,放到Eclipse(通常搭配MinGW/GCC编译器)里会有几个兼容性坑,我帮你逐个排查解决:
1. 链接库指令不生效,导致未定义符号错误
MSVC里的#pragma comment(lib, "IPHLPAPI.lib")是告诉链接器要链接的库,但MinGW/GCC根本不认这个语法,这是你遇到大量编译错误的核心原因之一。
解决办法:手动在Eclipse项目里添加需要的链接库:
- 右键你的项目 →
Properties→C/C++ Build→Settings→GCC C++ Linker→Libraries - 在
Libraries (-l)列表里添加两个库:iphlpapi和ws2_32(因为代码用到了Winsock相关头文件)
2. 代码里的无限循环问题(编译能过但运行会崩)
看你的代码,遍历适配器地址的while循环里,完全没写pCurrAddresses = pCurrAddresses->Next;,这会导致程序卡在第一个适配器的输出里无限循环,虽然编译可能通过,但运行肯定出问题。
修改代码:在循环的最后加上这行:
// 移动到下一个适配器地址,避免无限循环 pCurrAddresses = pCurrAddresses->Next;
3. 宽字符输出的兼容性问题
代码里用了%wS来打印宽字符串,但MinGW的printf对这个格式符支持不好,会导致输出乱码或者编译警告。
解决办法:把宽字符串的输出换成标准的宽字符打印方式:
比如把原来的:
printf("\tDNS Suffix: %wS\n", pCurrAddresses->DnsSuffix);
改成:
wprintf(L"\tDNS Suffix: %s\n", pCurrAddresses->DnsSuffix);
注意要给字符串加上L前缀,把它变成宽字符常量,同时用wprintf来输出宽字符内容。
4. 可选但建议:添加Winsock初始化代码
虽然GetAdaptersAddresses本身不需要显式初始化Winsock,但因为你包含了winsock2.h,最好在程序开头加上初始化代码,避免潜在的未知问题:
WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { printf("WSAStartup failed: %d\n", WSAGetLastError()); return 1; }
记得在程序结束前(return 0之前)加上清理代码:
WSACleanup();
5. 确保编译器环境正确
如果上面的步骤都做了还是报错,检查你的Eclipse项目是不是用的MinGW-w64编译器(旧版MinGW对Windows API的支持不全),并且项目的架构(32/64位)和你的系统匹配。
修改后的完整可运行代码
#include <windows.h> #include <winsock2.h> #include <iphlpapi.h> #include <iptypes.h> #include <stdio.h> #include <iostream> #define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x)) #define FREE(x) HeapFree(GetProcessHeap(), 0, (x)) int __cdecl main(int argc, char **argv) { // 初始化Winsock WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { printf("WSAStartup failed: %d\n", WSAGetLastError()); return 1; } DWORD dwSize = 0; DWORD dwRetVal = 0; unsigned int i = 0; ULONG flags = GAA_FLAG_INCLUDE_PREFIX; ULONG family = AF_UNSPEC; LPVOID lpMsgBuf = NULL; PIP_ADAPTER_ADDRESSES pAddresses = NULL; ULONG outBufLen = 0; PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL; PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = NULL; PIP_ADAPTER_MULTICAST_ADDRESS pMulticast = NULL; IP_ADAPTER_DNS_SERVER_ADDRESS *pDnServer = NULL; IP_ADAPTER_PREFIX *pPrefix = NULL; if (argc != 2) { printf(" Usage: getadapteraddresses family\n"); printf(" getadapteraddresses 4 (for IPv4)\n"); printf(" getadapteraddresses 6 (for IPv6)\n"); printf(" getadapteraddresses A (for both IPv4 and IPv6)\n"); exit(1); } if (atoi(argv[1]) == 4) family = AF_INET; else if (atoi(argv[1]) == 6) family = AF_INET6; outBufLen = sizeof(IP_ADAPTER_ADDRESSES); pAddresses = (IP_ADAPTER_ADDRESSES *) MALLOC(outBufLen); // 第一次调用获取所需缓冲区大小 if (GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen) == ERROR_BUFFER_OVERFLOW) { FREE(pAddresses); pAddresses = (IP_ADAPTER_ADDRESSES *) MALLOC(outBufLen); } if (pAddresses == NULL) { printf("Memory allocation failed for IP_ADAPTER_ADDRESSES struct\n"); WSACleanup(); exit(1); } printf("Memory allocated for GetAdapterAddresses = %d bytes\n", outBufLen); printf("Calling GetAdaptersAddresses function with family = "); if (family == AF_INET) printf("AF_INET\n"); if (family == AF_INET6) printf("AF_INET6\n"); if (family == AF_UNSPEC) printf("AF_UNSPEC\n\n"); // 第二次调用获取实际适配器数据 dwRetVal = GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen); if (dwRetVal == NO_ERROR) { pCurrAddresses = pAddresses; while (pCurrAddresses) { printf("\tLength of the IP_ADAPTER_ADDRESS struct: %ld\n", pCurrAddresses->Length); printf("\tIfIndex (IPv4 interface): %u\n", pCurrAddresses->IfIndex); printf("\tAdapter name: %s\n", pCurrAddresses->AdapterName); // 统计单播地址数量 pUnicast = pCurrAddresses->FirstUnicastAddress; if (pUnicast != NULL) { for (i = 0; pUnicast != NULL; i++) pUnicast = pUnicast->Next; printf("\tNumber of Unicast Addresses: %d\n", i); } else printf("\tNo Unicast Addresses\n"); // 统计任播地址数量 pAnycast = pCurrAddresses->FirstAnycastAddress; if (pAnycast) { for (i = 0; pAnycast != NULL; i++) pAnycast = pAnycast->Next; printf("\tNumber of Anycast Addresses: %d\n", i); } else printf("\tNo Anycast Addresses\n"); // 统计多播地址数量 pMulticast = pCurrAddresses->FirstMulticastAddress; if (pMulticast) { for (i = 0; pMulticast != NULL; i++) pMulticast = pMulticast->Next; printf("\tNumber of Multicast Addresses: %d\n", i); } else printf("\tNo Multicast Addresses\n"); // 统计DNS服务器地址数量 pDnServer = pCurrAddresses->FirstDnsServerAddress; if (pDnServer) { for (i = 0; pDnServer != NULL; i++) pDnServer = pDnServer->Next; printf("\tNumber of DNS Server Addresses: %d\n", i); } else printf("\tNo DNS Server Addresses\n"); // 输出宽字符内容 wprintf(L"\tDNS Suffix: %s\n", pCurrAddresses->DnsSuffix); wprintf(L"\tDescription: %s\n", pCurrAddresses->Description); wprintf(L"\tFriendly name: %s\n", pCurrAddresses->FriendlyName); // 输出物理地址(MAC地址) if (pCurrAddresses->PhysicalAddressLength != 0) { printf("\tPhysical address: "); for (i = 0; i < pCurrAddresses->PhysicalAddressLength; i++) { if (i == (pCurrAddresses->PhysicalAddressLength - 1)) printf("%.2X\n", (int) pCurrAddresses->PhysicalAddress[i]); else printf("%.2X-", (int) pCurrAddresses->PhysicalAddress[i]); } } printf("\tFlags: %ld\n", pCurrAddresses->Flags); printf("\tMtu: %lu\n", pCurrAddresses->Mtu); printf("\tIfType: %ld\n", pCurrAddresses->IfType); printf("\tOperStatus: %ld\n", pCurrAddresses->OperStatus); printf("\tIpv6IfIndex (IPv6 interface): %u\n", pCurrAddresses->Ipv6IfIndex); printf("\tZoneIndices (hex): "); for (i = 0; i < 16; i++) printf("%lx ", pCurrAddresses->ZoneIndices[i]); printf("\n"); // 移动到下一个适配器,避免无限循环 pCurrAddresses = pCurrAddresses->Next; } } else { printf("GetAdaptersAddresses failed with error: %ld\n", dwRetVal); if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwRetVal, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL)) { printf("Error message: %s\n", lpMsgBuf); LocalFree(lpMsgBuf); } } // 释放内存 if (pAddresses) FREE(pAddresses); // 清理Winsock WSACleanup(); return 0; }
内容的提问来源于stack exchange,提问作者Ali dashti




