You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用IP_ADAPTER_ADDRESSES时编译报错求助

解决Eclipse中编译MSDN GetAdaptersAddresses示例代码的报错问题

作为刚接触C++和Windows API的新手,遇到这种编译报错太正常了——MSDN的示例代码是针对Visual Studio(MSVC编译器)写的,放到Eclipse(通常搭配MinGW/GCC编译器)里会有几个兼容性坑,我帮你逐个排查解决:

1. 链接库指令不生效,导致未定义符号错误

MSVC里的#pragma comment(lib, "IPHLPAPI.lib")是告诉链接器要链接的库,但MinGW/GCC根本不认这个语法,这是你遇到大量编译错误的核心原因之一。

解决办法:手动在Eclipse项目里添加需要的链接库:

  • 右键你的项目 → PropertiesC/C++ BuildSettingsGCC C++ LinkerLibraries
  • Libraries (-l)列表里添加两个库:iphlpapiws2_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

火山引擎 最新活动