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.
-std=gnu17
vs -std=c17
:-Werror
from the build command so that it compiles with that error as a warning instead of as an error.-std=c17
so that you get the extra features provided by gcc instead of being limited to the C standard.-std=gnu17
instead of -std=c17
(thanks, @ikegami!)-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
#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>
.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.
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
.
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 eitherAF_INET
orAF_INET6
, as appropriate for the type of address being converted.cp
is a pointer to the input string, andbuf
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()
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));
}
}