如何修复 C 中的错误或警告:“函数‘inet_aton’的隐式声明”;您的意思是“inet_pton”吗?

发布于 2025-01-20 11:18:50 字数 1672 浏览 3 评论 0 原文

我无法使用 inet_aton() << /a>要将ASCII IP地址转换为“ 192.168.0.1” 在网络字节顺序中的 struct in_addr 地址,因为我无法将代码编译。

我正在此文件中工作:

在这里是我的构建命令:

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 包括 arpa/inet.h ,其中包含<<的声明代码> inet_aton(),在我的源文件的顶部,所以我知道这不是问题:

#include <arpa/inet.h>

I am unable to use inet_aton() to convert an ASCII IP address such as "192.168.0.1" to a struct in_addr address in network byte order because I cannot get my code to compile.

I'm working in this file: socket__geeksforgeeks_udp_server_GS_edit_GREAT.c

Here is my build command:

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

Here is my command and error output:

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

The part I want to fix is:

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

I am including arpa/inet.h, which contains the declaration for inet_aton(), at the top of my source file, so I know that is not the problem:

#include <arpa/inet.h>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

并安 2025-01-27 11:18:50

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

(如果您偶然发现这个问题,请首先确保您的文件顶部有 #include ,如问题中所述。)

事实证明,将-std=c17 比仅仅保留该部分更具限制性。如果没有 -std=c17,gcc 编译器将包含更多不属于 C 标准的功能,包括 POSIX 功能、gcc 扩展和特殊的 Linux 系统功能。因此,使用 -std=c17 会导致 inet_aton() 的声明从 排除,即使它本来会被包含在内。

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

  1. [不推荐,因为这是一个 hack,而不是修复] 从以下位置删除 -Werror构建命令,以便将该错误作为警告而不是错误进行编译。
  2. 删除 -std=c17 以便您获得 gcc 提供的额外功能,而不是局限于 C 标准。
  3. [绝佳选择] 使用限制较少的 -std=gnu17 而不是 -std=c17 (谢谢,@ikegami!
  4. [另一个不错的选择]添加-D_DEFAULT_SOURCE 到您的构建命令中,为整个程序定义宏 _DEFAULT_SOURCE,以便 gcc 允许来自 inet_aton() 为您提供(更多信息请参见下文)。现在这是我的完整构建命令:
    gcc -Wall -Wextra -Werror -O3 -std=c17 -D_DEFAULT_SOURCE \
    socket__geeksforgeeks_udp_server_GS_edit_GREAT.c -o bin/server \
    -lm &&容器/服务器
    
  5. [上述选项的替代方法] 将 #define _DEFAULT_SOURCE 添加到主源文件的顶部之前,包括任何标头,以便它在包含标头之前定义,从而允许在包含 的位置使用 inet_aton()
  6. [无论我也使用上面的哪个选项,我都计划这样做]使用更好的 POSIX inet_pton() “互联网演示(文本)到网络(二进制)格式”功能(请参阅 此处此处)而不是非 POSIX inet_aton() “互联网 ascii 字符串到网络”函数(参见 此处)。请参阅下面的更多内容。

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

gcc 中的“功能测试宏”

上面的选项 4 和 5 如何工作?我了解到它们是 gcc 的“功能测试宏”系统的一部分。在这里阅读所有相关内容: https://man7.org/linux/手册页/man7/feature_test_macros.7.html。本质上,当您包含头文件时,GNU glibc 库实现的某些功能被排除,除非在包含该头文件之前定义了某些“功能测试宏”。

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

glibc 的功能测试宏要求(请参阅 feature_test_macros(7)< /a>):

inet_aton()inet_ntoa()

  • 自 glibc 2.19 起:
    • _DEFAULT_SOURCE
  • 在 glibc 2.19 及之前版本中:
    • <代码>_BSD_SOURCE || _BSD_SOURCE

因此,使用 ldd --version 检查您的 glibc 版本。我的显示 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: 部分适用于我,我必须定义“功能测试宏”_DEFAULT_SOURCE 在包含任何标头之前的源代码中(我上面的选项 5), 在构建命令中(我上面的选项 4)包含这些功能,包括inet_aton()

简单地省略 -std=c17 也可以,因为 feature_test_macros 手册页(也可通过 man feature_test_macros 在命令行中使用)指出:

请注意,如下所述,某些功能测试宏是默认定义的,因此可能并不总是需要显式指定概要中显示的功能测试宏。< /p>

和:

_DEFAULT_SOURCE(自 glibc 2.19 起)

可以定义此宏以确保“默认”
即使默认值会提供定义
否则会被禁用,就像个别宏时发生的情况一样
显式定义,或者编译器在其中调用
其“标准”模式(例如,cc -std=c99)。定义
_DEFAULT_SOURCE 未定义其他单独的宏
或以其中一种“标准”模式调用编译器
没有效果。

“默认”定义包括以下要求的定义
POSIX.1-2008 和 ISO C99,以及各种定义
最初源自 BSD 和 System V。在 glibc 2.19 上
之前,这些默认值大致相同
明确定义以下内容:

cc -D_BSD_SOURCE -D_SVID_SOURCE
-D_POSIX_C_SOURCE=200809

请注意,它提到了 -std=c99。这个概念适用于我对 -std=c17 的使用,因此我必须定义 _DEFAULT_SOURCE 来对抗 -std=c17 创建的功能删除效果。代码>.

只需使用 POSIX 兼容的 inet_pton() 而不是非 POSIX inet_aton()

最后,这是一个比使用非 POSIX 更好的选择 - POSIX函数inet_aton()(“ASCII字符串到网络”函数)是使用POSIX函数inet_pton()(“表示字符串到网络”函数)。

此源(https://man7.org/linux/man-pages /man3/inet.3.html)说(强调):

inet_aton() 未在 POSIX.1 中指定,但在大多数系统上可用

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

另请参阅 gcc glibc 一页用户手册。以下是 int inet_pton (int af, const char *cp, void *buf) 部分的链接:https://www.gnu.org/software/libc/manual/html_mono/libc.html#index-inet_005fpton(添加了重点):

此函数将互联网地址(IPv4 或 IPv6)从表示(文本)格式转换为网络(二进制)格式af 应为 AF_INETAF_INET6,具体取决于要转换的地址类型。 cp 是指向输入字符串的指针,buf 是指向结果缓冲区的指针。调用者有责任确保缓冲区足够大。

inet_aton()inet_pton() 的完整示例

对于我的完整示例代码(包括错误检查),请在此文件中搜索 inet_aton inet_pton (推荐),在我的 eRCAGuy_hello_world 仓库:socket__geeksforgeeks_udp_server_GS_edit_GREAT.c

示例:这是我的 inet_pton()< /a> 示例代码:

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));
    }
}

After a bunch of study, I figured it out!

(If you are stumbling upon this question, first ensure you have #include <arpa/inet.h> at the top of your file, as already stated in the question.)

It turns out that putting -std=c17 is more-restrictive than just leaving that part off. WithOUT -std=c17, the gcc compiler includes many more features which are not part of the C standard, including POSIX features, gcc extensions, and special Linux system features. So, using -std=c17 causes the declaration of inet_aton() to get excluded from <arpa/inet.h>, even though it would otherwise be included.

Here are the various fixes, incl. using -std=gnu17 vs -std=c17:

  1. [Not recommended, since this is a hack, not a fix] Remove -Werror from the build command so that it compiles with that error as a warning instead of as an error.
  2. Remove -std=c17 so that you get the extra features provided by gcc instead of being limited to the C standard.
  3. [GREAT OPTION] Use the less-restrictive -std=gnu17 instead of -std=c17 (thanks, @ikegami!)
  4. [ANOTHER GREAT OPTION] Add -D_DEFAULT_SOURCE to your build command to define the macro _DEFAULT_SOURCE for your entire program, so that gcc will allow in inet_aton() from <arpa/inet.h> for you (more on this below). Here is my full build command now:
    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. [Alternative to the option just above] Add #define _DEFAULT_SOURCE to the top of your main source file before including any headers, so that it is defined before your headers get included, thereby allowing in inet_aton() from where you include <arpa/inet.h>.
  6. [I plan on doing this regardless of which option above I also use] Use the better POSIX inet_pton() "internet presentation (textual) to network (binary) format" function (see here and here) instead of the non-POSIX inet_aton() "internet ascii string to network" function (see here). See more on this below.

Any of those options work. I recommend option 3, 4, or 5, but I prefer 3 the most, and 4 after that. In all cases, I plan on also implementing option 6, however.

"Feature test macros" in gcc

How do options 4 and 5 above work? I learned they are part of gcc's "feature test macros" system. Read all about it here: https://man7.org/linux/man-pages/man7/feature_test_macros.7.html. In essence, certain features of gnu's glibc library implementation are excluded as you include header files unless certain "feature test macros" are defined before you include that header.

Go look at the man page for inet_aton(): https://man7.org/linux/man-pages/man3/inet.3.html. It states at the bottom of the "SYNOPSIS" section at the top of the page:

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

So, check your version of glibc with ldd --version. Mine shows 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.

That means the part that says Since glibc 2.19: above applies to me, and I must define the "feature test macro" _DEFAULT_SOURCE in the source code before including any headers (my option 5 above), or in the build command (my option 4 above) to include these features, including inet_aton().

Simply leaving off -std=c17 also works because the feature_test_macros man page (also available at the command-line via man feature_test_macros) states:

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.

and:

_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

Notice that it mentions -std=c99. That concept applies to my usage of -std=c17, so I have to define _DEFAULT_SOURCE to counter the feature-removal effect created by -std=c17.

Just use the POSIX-compliant inet_pton() instead of the non-POSIX inet_aton()

Lastly, an even better option than using the non-POSIX function inet_aton() ("ASCII string to network" function) is to use the POSIX function inet_pton() ("presentation string to network" function).

This source (https://man7.org/linux/man-pages/man3/inet.3.html) says (emphasis added):

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

inet_pton() is even better, and available with my original build command in the question, and is described here: https://man7.org/linux/man-pages/man3/inet_pton.3.html. It does not require any gcc feature test macros to include it, and it has more functionality than inet_aton and handles both IPv4 address families (AF_INET) and IPv6 address families (AF_INET6).

See also the gcc glibc one-page user manual. Here is the link to the int inet_pton (int af, const char *cp, void *buf) part: https://www.gnu.org/software/libc/manual/html_mono/libc.html#index-inet_005fpton (emphasis added):

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.

Full example of inet_aton() and inet_pton()

For my full example code, including error checking, search this file for inet_aton and inet_pton (recommended), in this file from my eRCaGuy_hello_world repo here: socket__geeksforgeeks_udp_server_GS_edit_GREAT.c.

Example: here is my inet_pton() example code:

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));
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文