简体   繁体   中英

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

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>

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 (eg, 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));
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM