如何修复 C 中的错误或警告:"implicit declaration of function ‘inet_aton’; did you mean ‘inet_pton’?"

How to fix error or warning in C: "implicit declaration of function ‘inet_aton’; did you mean ‘inet_pton’?"

我无法使用 inet_aton() 将 ASCII IP 地址(例如 "192.168.0.1" 转换为网络字节顺序的 struct in_addr 地址,因为我无法编译我的代码。

我正在处理这个文件:socket__geeksforgeeks_udp_server_GS_edit_GREAT.c

这是我的构建命令:

gcc -Wall -Wextra -Werror -O3 -std=c17 \
socket__geeksforgeeks_udp_server_GS_edit_GREAT.c -o bin/server \
-lm && bin/server

这是我的命令和错误输出:

eRCaGuy_hello_world/c$ gcc -Wall -Wextra -Werror -O3 -std=c17 socket__geeksforgeeks_udp_server_GS_edit_GREAT.c -o bin/server -lm && bin/server
socket__geeksforgeeks_udp_server_GS_edit_GREAT.c: In function ‘main’:
socket__geeksforgeeks_udp_server_GS_edit_GREAT.c:159:15: error: implicit declaration of function ‘inet_aton’; did you mean ‘inet_pton’? [-Werror=implicit-function-declaration]
     retcode = inet_aton("127.0.0.1", &addr_server.sin_addr);
               ^~~~~~~~~
               inet_pton
cc1: all warnings being treated as errors

我要修复的部分是:

implicit declaration of function ‘inet_aton’; did you mean ‘inet_pton’? [-Werror=implicit-function-declaration]

I am including arpa/inet.h,它包含 inet_aton() 的声明,在我的源文件的顶部,所以我知道那不是问题:

#include <arpa/inet.h>

经过一番研究,我明白了!

(如果您遇到这个问题,请首先确保您的文件顶部有 #include <arpa/inet.h>,如问题中所述。)

事实证明,放置 -std=c17more-restrictive 而不是只留下那部分。有了 OUT -std=c17,gcc 编译器包含更多 不是 C 标准的一部分的特性,包括 POSIX 特性、gcc 扩展和特殊的 Linux 系统特点。因此,使用 -std=c17 会导致 inet_aton() 的声明从 <arpa/inet.h> 中被 排除 ,即使它本来会被 包含。

这是各种修复,包括。使用 -std=gnu17-std=c17:

  1. [不推荐,因为这是 hack,而不是修复] 从构建命令中删除 -Werror,以便它编译时将该错误作为 warning作为错误.
  2. 删除 -std=c17 以便您获得 gcc 提供的额外功能,而不是局限于 C 标准。
  3. [最佳选择] 使用 less-restrictive -std=gnu17 而不是 -std=c17 (thanks, @ikegami!)
  4. [另一个不错的选择] 将 -D_DEFAULT_SOURCE 添加到您的构建命令以定义整个程序的宏 _DEFAULT_SOURCE,这样 gcc 将允许 inet_aton() 来自 <arpa/inet.h> 给你(下面有更多内容)。这是我现在的完整构建命令:
    gcc -Wall -Wextra -Werror -O3 -std=c17 -D_DEFAULT_SOURCE \
    socket__geeksforgeeks_udp_server_GS_edit_GREAT.c -o bin/server \
    -lm && bin/server
    
  5. [替代上述选项] 将 #define _DEFAULT_SOURCE 添加到主源文件的顶部 before 包括 any headers,以便在包含 headers 之前定义它,从而允许从包含 <arpa/inet.h>.
  6. 的地方进入 inet_aton()
  7. [无论我还使用上面的哪个选项,我都计划这样做]使用更好的 POSIX inet_pton()“互联网演示(文本)到网络(二进制)格式”功能(参见 here and here) instead of the non-POSIX inet_aton() "internet ascii string to network" function (see here).请参阅下面的详细信息。

这些选项中的任何一个都有效。我推荐选项 3、4 或 5,但我最喜欢 3,其次是 4。然而,在 所有 情况下,我计划 实施选项 6。

gcc 中的“功能测试宏”

上面的选项 4 和 5 如何工作?我了解到它们是 gcc 的“功能测试宏”系统的一部分。在这里阅读所有相关信息:https://man7.org/linux/man-pages/man7/feature_test_macros.7.html。本质上,gnu 的 glibc 库实现的某些功能被 排除 因为你包括 header 文件,除非某些“功能测试宏”被定义 before 你包括 header.

请查看 inet_aton()man 页面:https://man7.org/linux/man-pages/man3/inet.3.html。它在页面顶部“SYNOPSIS”部分的底部指出:

Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

inet_aton(), inet_ntoa():

  • Since glibc 2.19:
    • _DEFAULT_SOURCE
  • In glibc up to and including 2.19:
    • _BSD_SOURCE || _BSD_SOURCE

所以,check your version of glibc with ldd --version。我的显示 2.27:

$ ldd --version
ldd (Ubuntu GLIBC 2.27-3ubuntu1.5) 2.27
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.

这意味着上面说 Since glibc 2.19: 的部分适用于我,我必须在包含任何 header 之前在源代码中定义“功能测试宏”_DEFAULT_SOURCE (我上面的选项 5), 在构建命令(我上面的选项 4)中包含这些功能,包括 inet_aton().

简单地停止 -std=c17 也有效,因为 feature_test_macros man page(也可以通过 man feature_test_macros 在 command-line 上获得)声明:

Note that, as described below, some feature test macros are defined by default, so that it may not always be necessary to explicitly specify the feature test macro(s) shown in the SYNOPSIS.

和:

_DEFAULT_SOURCE (since glibc 2.19)

This macro can be defined to ensure that the "default" definitions are provided even when the defaults would otherwise be disabled, as happens when individual macros are explicitly defined, or the compiler is invoked in one of its "standard" modes (e.g., cc -std=c99). Defining _DEFAULT_SOURCE without defining other individual macros or invoking the compiler in one of its "standard" modes has no effect.

The "default" definitions comprise those required by POSIX.1-2008 and ISO C99, as well as various definitions originally derived from BSD and System V. On glibc 2.19 and earlier, these defaults were approximately equivalent to explicitly defining the following:

cc -D_BSD_SOURCE -D_SVID_SOURCE
-D_POSIX_C_SOURCE=200809

注意它提到了 -std=c99。这个概念适用于我对 -std=c17 的使用,所以我必须定义 _DEFAULT_SOURCE 来抵消 -std=c17.

产生的 feature-removal 效果

只需使用 POSIX-compliant inet_pton() 而不是 non-POSIX inet_aton()

最后,比使用 non-POSIX 函数 inet_aton()(“ASCII 字符串到网络”函数)更好的选择是使用POSIX 函数 inet_pton()(“向网络显示字符串”函数)。

这个消息来源 (https://man7.org/linux/man-pages/man3/inet.3.html) 说(强调):

inet_aton() is not specified in POSIX.1, but is available on most systems.

inet_pton() 更好,可以在问题中使用我的原始构建命令,并在此处进行描述:https://man7.org/linux/man-pages/man3/inet_pton.3.html。它 不需要 需要任何 gcc 功能测试宏来包含它,并且它比 inet_aton 具有更多的功能并且可以处理 IPv4 地址系列 (AF_INET) 和 IPv6 地址家庭(AF_INET6)。

另请参阅 gcc glibc one-page 用户手册。这是 int inet_pton (int af, const char *cp, void *buf) 部分的 link:https://www.gnu.org/software/libc/manual/html_mono/libc.html#index-inet_005fpton(强调):

This function converts an Internet address (either IPv4 or IPv6) from presentation (textual) to network (binary) format. af should be either AF_INET or AF_INET6, as appropriate for the type of address being converted. cp is a pointer to the input string, and buf is a pointer to a buffer for the result. It is the caller’s responsibility to make sure the buffer is large enough.

inet_aton()inet_pton()

的完整示例

对于我的完整示例代码,包括错误检查,在这个文件中搜索 inet_atoninet_pton(推荐),来自我的 eRCaGuy_hello_world repo here: socket__geeksforgeeks_udp_server_GS_edit_GREAT.c.

示例:这是我的 inet_pton() 示例代码:

int retcode;

// ...

retcode = inet_pton(AF_INET, "127.0.0.1", &addr_server.sin_addr); // <--- Option 3/3 to set the IP address
if (retcode != 1)
{
    printf("`inet_pton()` failed! ");
    if (retcode == 0)
    {
        printf("The source IP address string does not contain a character string representing "
               "a valid network address in the specified address family.\n");
    }
    else if (retcode == -1)
    {
        printf("Invalid address family (AF) parameter was passed-in as the 1st argument. "
               "errno = %i: %s\n", errno, strerror(errno));
    }
}