Linux - Feature Test Macros and Dynamic Linking - c

The C standard library includes a method, strerror_r (https://linux.die.net/man/3/strerror_r).
Depending on the "feature test macros" defined at compilation time, and compiling vs the GNU standard headers, one of two definitions gets included:
int strerror_r(int errnum, char buf, size_t buflen);
/ XSI-compliant */
char *strerror_r(int errnum, char buf, size_t buflen);
/ GNU-specific */
The XSI-compliant version of strerror_r() is provided if:
(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE
Otherwise, the GNU-specific version is provided.
Assuming I'm dynamically linking my application vs. the standard library, how does the linker correctly link vs. the proper definition of the function?

One of them is actually called __xpg_strerror_r and is redirected to be used as strerror_r if needed, see:
https://code.woboq.org/userspace/glibc/string/string.h.html#409

Related

stdarg and printf() in C

The <stdarg.h> header file is used to make functions accept undefined number of arguments, right?
So, the printf() funtion of <stdio.h> must be using <stdarg.h> to accept avariable number of arguments(please correct me if I'm mistaken).
I found the following lines in the stdio.h file of gcc:
#if defined __USE_XOPEN || defined __USE_XOPEN2K8
# ifdef __GNUC__
# ifndef _VA_LIST_DEFINED
typedef _G_va_list va_list;
# define _VA_LIST_DEFINED
# endif
# else
# include <stdarg.h>//////////////////////stdarg.h IS INCLUDED!///////////
# endif
#endif
I can't understand most of what's in it, but it appears to be including <stdarg.h>
So, if printf() uses <stdarg.h> for accepting variable number of arguments and stdio.h has printf(), a C program using printf() need not include <stdarg.h> does it?
I tried a program which had printf() and a user-defined function accepting variable number of arguments.
The program I tried is:
#include<stdio.h>
//#include<stdarg.h>///If this is included, the program works fine.
void fn(int num, ...)
{
va_list vlist;
va_start(vlist, num);//initialising va_start (predefined)
int i;
for(i=0; i<num; ++i)
{
printf("%d\n", va_arg(vlist, int));
}
va_end(vlist);//clean up memory
}
int main()
{
fn(3, 18, 11, 12);
printf("\n");
fn(6, 18, 11, 32, 46, 01, 12);
return 0;
}
It works fine if <stdarg.h> is included but otherwise generates the following error:
40484293.c:13:38: error: expected expression before ‘int’
printf("%d\n", va_arg(vlist, int));//////error: expected expression before 'int'/////////
^~~
How is this?
Or is it that printf() doesn't use <stdarg.h> for accepting variable number of arguments?
If so, how is it done?
Consider:
stdio.h:
int my_printf(const char *s, ...);
Do you need <stdarg.h>? No, you don't. ... is part of the grammar of the language - it's "built-in". However, as soon as you want to do anything meaningful and portable with such list of arguments, you need the names defined in there: va_list, va_start and so on.
stdio.c:
#include "stdio.h"
#include "stdarg.h"
int my_printf(const char *s, ...)
{
va_list va;
va_start(va, s);
/* and so on */
}
But this will be necessary, essentially, in the implementation of your libc which is something you don't see unless you compile the library on your own. What you instead get is the libc shared library, which has already been compiled to machine code.
So, if printf() uses for accepting variable number of
arguments and stdio.h has printf(), a C program using printf() need
not include does it?
Even if it were so, you cannot rely on that, otherwise your code is ill-formed: you must include all the headers anyway if a name belonging to them is used, regardless whether the implementation already does that or not.
I'm first going to answer your question in terms of the C standard, because that is what tells you how you should write your code.
The C standard requires stdio.h to "behave as-if" it does not include stdarg.h. In other words, the macros va_start, va_arg, va_end, and va_copy, and the type va_list, are required not to be made available by including stdio.h. In other other words, this program is required not to compile:
#include <stdio.h>
unsigned sum(unsigned n, ...)
{
unsigned total = 0;
va_list ap;
va_start(ap, n);
while (n--) total += va_arg(ap, unsigned);
va_end(ap);
return total;
}
(This is a difference from C++. In C++, all standard library headers are allowed, but not required, to include each other.)
It is true that the implementation of printf (probably) uses the stdarg.h mechanism to access its arguments, but that just means that some files in the source code for the C library ("printf.c", perhaps) need to include stdarg.h as well as stdio.h; that doesn't affect your code.
It is also true that stdio.h declares functions that take va_list-typed arguments. If you look at those declarations, you will see that they actually use a typedef name that begins with either two underscores, or an underscore and a capital letter: for instance, with the same stdio.h you are looking at,
$ egrep '\<v(printf|scanf) *\(' /usr/include/stdio.h
extern int vprintf (const char *__restrict __format, _G_va_list __arg);
extern int vscanf (const char *__restrict __format, _G_va_list __arg);
All names that begin with two underscores, or an underscore and a capital letter, are reserved for the implementation - stdio.h is allowed to declare as many such names as it wants. Conversely, you, the application programmer, are not allowed to declare any such names, or use the ones that the implementation declares (except the subset that are documented, such as _POSIX_C_SOURCE and __GNUC__). The compiler will let you do it, but the effects are undefined.
Now I'm going to talk about the thing you quoted from stdio.h. Here it is again:
#if defined __USE_XOPEN || defined __USE_XOPEN2K8
# ifdef __GNUC__
# ifndef _VA_LIST_DEFINED
typedef _G_va_list va_list;
# define _VA_LIST_DEFINED
# endif
# else
# include <stdarg.h>
# endif
#endif
To understand what this is doing, you need to know three things:
Recent "issues" of POSIX.1, the official specification of what it means to be a "Unix" operating system, add va_list to the set of things stdio.h is supposed to define. (Specifically, in Issue 6, va_list is defined by stdio.h as an "XSI" extension, and in Issue 7 it's mandatory.) This code defines va_list, but only if the program has requested Issue 6+XSI or Issue 7 features; that's what #if defined __USE_XOPEN || defined __USE_XOPEN2K8 means. Notice that it is using _G_va_list to define va_list, just as, elsewhere, it used _G_va_list to declare vprintf. _G_va_list is already available somehow.
You cannot write the same typedef twice in the same translation unit. If stdio.h defined va_list without somehow notifying stdarg.h not to do it again,
#include <stdio.h>
#include <stdarg.h>
would not compile.
GCC comes with a copy of stdarg.h, but it does not come with a copy of stdio.h. The stdio.h you are quoting comes from GNU libc, which is a separate project under the GNU umbrella, maintained by a separate (but overlapping) group of people. Crucially, GNU libc's headers cannot assume that they are being compiled by GCC.
So, the code you quoted defines va_list. If __GNUC__ is defined, which means the compiler is either GCC or a quirk-compatible clone, it assumes that it can communicate with stdarg.h using a macro named _VA_LIST_DEFINED, which is defined if and only if va_list is defined — but being a macro, you can check for it with #if. stdio.h can define va_list itself and then define _VA_LIST_DEFINED, and then stdarg.h won't do it, and
#include <stdio.h>
#include <stdarg.h>
will compile fine. (If you look at GCC's stdarg.h, which is probably hiding in /usr/lib/gcc/something/something/include on your system, you will see the mirror image of this code, along with a hilariously long list of other macros that also mean "don't define va_list, I already did that" for other C libraries that GCC can, or could once, be used with.)
But if __GNUC__ is not defined, then stdio.h assumes it does not know how to communicate with stdarg.h. But it does know that it's safe to include stdarg.h twice in the same file, because the C standard requires that to work. So in order to get va_list defined, it just goes ahead and includes stdarg.h, and thus, the va_* macros that stdio.h isn't supposed to define will also be defined.
This is what the HTML5 people would call a "willful violation" of the C standard: it's wrong, on purpose, because being wrong in this way is less likely to break real-world code than any available alternative. In particular,
#include <stdio.h>
#include <stdarg.h>
is overwhelmingly more likely to appear in real code than
#include <stdio.h>
#define va_start(x, y) /* something unrelated to variadic functions */
so it's much more important to make the first one work than the second, even though both are supposed to work.
Finally, you might still be wondering where the heck _G_va_list came from. It's not defined anywhere in stdio.h itself, so it must either be a compiler intrinsic, or be defined by one of the headers stdio.h includes. Here's how you find out everything that a system header includes:
$ echo '#include <stdio.h>' | gcc -H -xc -std=c11 -fsyntax-only - 2>&1 | grep '^\.'
. /usr/include/stdio.h
.. /usr/include/features.h
... /usr/include/x86_64-linux-gnu/sys/cdefs.h
.... /usr/include/x86_64-linux-gnu/bits/wordsize.h
... /usr/include/x86_64-linux-gnu/gnu/stubs.h
.... /usr/include/x86_64-linux-gnu/gnu/stubs-64.h
.. /usr/lib/gcc/x86_64-linux-gnu/6/include/stddef.h
.. /usr/include/x86_64-linux-gnu/bits/types.h
... /usr/include/x86_64-linux-gnu/bits/wordsize.h
... /usr/include/x86_64-linux-gnu/bits/typesizes.h
.. /usr/include/libio.h
... /usr/include/_G_config.h
.... /usr/lib/gcc/x86_64-linux-gnu/6/include/stddef.h
.... /usr/include/wchar.h
... /usr/lib/gcc/x86_64-linux-gnu/6/include/stdarg.h
.. /usr/include/x86_64-linux-gnu/bits/stdio_lim.h
.. /usr/include/x86_64-linux-gnu/bits/sys_errlist.h
I used -std=c11 to make sure I was not compiling in POSIX Issue 6+XSI nor Issue 7 modes, and yet we see stdarg.h in this list anyway — not included directly by stdio.h, but by libio.h, which is not a standard header. Let's have a look in there:
#include <_G_config.h>
/* ALL of these should be defined in _G_config.h */
/* ... */
#define _IO_va_list _G_va_list
/* This define avoids name pollution if we're using GNU stdarg.h */
#define __need___va_list
#include <stdarg.h>
#ifdef __GNUC_VA_LIST
# undef _IO_va_list
# define _IO_va_list __gnuc_va_list
#endif /* __GNUC_VA_LIST */
So libio.h includes stdarg.h in a special mode (here's another case where implementation macros are used to communicate between system headers), and expects it to define __gnuc_va_list, but it uses it to define _IO_va_list, not _G_va_list. _G_va_list is defined by _G_config.h...
/* These library features are always available in the GNU C library. */
#define _G_va_list __gnuc_va_list
... in terms of __gnuc_va_list. That name is defined by stdarg.h:
/* Define __gnuc_va_list. */
#ifndef __GNUC_VA_LIST
#define __GNUC_VA_LIST
typedef __builtin_va_list __gnuc_va_list;
#endif
And __builtin_va_list, finally, is an undocumented GCC intrinsic, meaning "whatever type is appropriate for va_list with the current ABI".
$ echo 'void foo(__builtin_va_list x) {}' |
gcc -xc -std=c11 -fsyntax-only -; echo $?
0
(Yes, GNU libc's implementation of stdio is way more complicated than it has any excuse for being. The explanation is that back in elder days people tried to make its FILE object directly usable as a C++ filebuf. That hasn't worked in decades — in fact, I'm not sure if it ever worked; it had been abandoned before EGCS, which is as far back as I know the history — but there are many, many vestiges of the attempt hanging around still, either for binary backward compatibility or because nobody has gotten around to cleaning them up.)
(Yes, if I'm reading this correctly, GNU libc's stdio.h won't work right with a C compiler whose stdarg.h doesn't define __gnuc_va_list. This is abstractly wrong, but harmless; anyone wanting a shiny new non-GCC-compatible compiler to work with GNU libc is going to have a whole lot more things to worry about.)
stdarg header file is used to make functions accept undefined number
of arguments, right?
No, <stdarg.h> just exposes an API that should be used to access extra arguments. There is no necessity to include that header if you want just declare function that accepts variable number of arguments, like this:
int foo(int a, ...);
This is a language feature and requires no extra declarations / definitions.
I found the following lines in the stdio.h file of gcc:
#if defined __USE_XOPEN || defined __USE_XOPEN2K8
# ifdef __GNUC__
# ifndef _VA_LIST_DEFINED
typedef _G_va_list va_list;
# define _VA_LIST_DEFINED
# endif
# else
# include <stdarg.h>//////////////////////stdarg.h IS INCLUDED!///////////
# endif
#endif
I guess this stuff is required only to declare things like vprintf() without internal including of <stdarg.h>:
int vprintf(const char *format, va_list ap);
To top it off:
Header that declares function with variable number of arguments shouldn't include <stdarg.h> internally.
Implementation of function with variable number of arguments must include <stdarg.h> and use va_list API to access extra arguments.
No, to use printf() all you need is #include <stdio.h>. There's no need for stdarg because printf is already compiled. The compiler only needs to see a prototype for printf to know that it is variadic (derived from the ellipsis ... in the prototype). If you look at the stdio library source code for printf you'll see the <stdarg.h> being included.
If you want to write your own variadic function, you must #include <stdarg.h> and use its macros accordingly. As you can see, if you forget to do that, the va_start/list/end symbols are unknown to the compiler.
If you want to see a real implementation of printf, look at the code in FreeBSD's standard I/O source, along with the source for vfprintf.
Fundamentals of splitting a module into a header file and a source file:
In the header file, you put only the interface of your module
In the source file, you put the implementation of your module
So even if the implementation of printf makes use of va_arg as you speculate:
In stdio.h, the author only declared int printf(const char* format, ...);
In stdio.c, the author implemented printf using va_arg
This implementation of stdio.h does not include stdarg.h when compiled with gcc. It works by magic that compiler writers always have up their sleeves.
Your C source files must include every system header they reference anyway. It is a requirement of the C standard. That is, if your source code requires definitions present in stdarg.h, it must contain #include <stdarg.h> directive either directly, or in one of your header files that it includes. It cannot rely on stdarg.h being included in other standard headers, even if they do in fact include it.
The <stdarg.h> file is required to be included only if you are going to implement a variable number of arguments function. It's not required to be able to use printf(3) and friends. Only if you are going to process arguments on a variable number of args function, you'll need the va_list type, and the va_start, va_arg and va_end macros. So, only then you'll need to forcibly include that file.
In general, you are not warranted that <stdarg.h> will be included with just including <stdio.h> Indeed, the code you cite only includes it, if __GNU_C__ is not defined (which I suspect, is the case, so it's not included in your case) and this macro is defined if you are using the gcc compiler.
If you are going to create variable argument passing functions in your code, the best approach is not to expect another included file to include it, but do it yourself (as a client for the requested functionality you are) everywhere you are using the va_list type, or va_start, va_arg or va_end macros.
In the past, there was some confusion about double inclusion, as some header files were not protected from double inclusion (including twice or more times the same include file produced errors about doubly defined macros or similar and you had to go with care) but today, this is not an issue and normally all standard header fields are protected from double inclusion.
Okay, there is the "regular" printf family: printf, fprintf, dprintf, sprintf, and snprintf.
And then there's the variable number of arguments printf family: vprintf, vfprintf, vdprintf, vsprintf, and vsnprintf.
To use a variable list of arguments with either, you need to declare stdarg.h.
stdarg.h defines all the macros you're using: va_list, va_start, va_arg, va_end, and va_copy.

Why add a "_" before parameter list

When I read some code which run on linux and is compiled by gcc, I meet a declaration like that:
void* (*func_name) _((void *buf, int size))
The BGET source code is that:
void bectl _((int (*compact)(bufsize sizereq , int sequence),
void *(*acquire)(bufsize size),
void *(*release)(void *buf),
bufsize pool_incr));
void bectl(compact, acquire, release, pool_incr)
int(*compact) _((bufsize sizereq, int sequence));
void *(*acquire) _((bufsize size));
void (*release) _((void *buf));
bufsize pool_incr;
{
}
The question is that I don't know why add "_" before parameter list.
_ is a macro intended to allow the code to use prototypes (function declarations that specify the types of the parameters) while still being compatible with pre-ANSI compilers that don't support prototypes.
Note that _ is a valid identifier. However, all identifiers starting with _ are reserved for use at file scope, so this is one more reason the code is potentially non-portable.
The code you're reading is apparently BGET, available here. (It would have been helpful to cite the source in your question.) If you look at the bget.h header file (last updated in 1995), you'll see:
#ifndef _
#ifdef PROTOTYPES
#define _(x) x /* If compiler knows prototypes */
#else
#define _(x) () /* It it doesn't */
#endif /* PROTOTYPES */
#endif
Today, 21 years later, there are very few C compilers in use that don't support prototypes, so the need for such macros is largely obsolete. But even the latest ISO C standard, published in 2011, still supports old-style non-prototype functions.
Note that there's nothing in the source that actually defines the PROTOTYPES macro, so if you want to compile the code with prototypes enabled (to get additional compile-time checking), you'll need to manually edit the makefile, changing this:
COPTS = -O
to this:
COPTS = -O -DPROTOTYPES
Even with that change, compilation still fails because of the invalid redeclaration of malloc. The code needs some work to bring it up to modern standards.

Why do I get in my timespec-array the error "array type has incomplete element type"?

I got a problem with my C-Code in Eclipse. To be specific my sleep-method does produce an error in the line where the timespec is stated. May you guys can tell me what I did wrong? Here's the code:
void sleep(double time) {
nanosleep(
(struct timespec[]) { {time,((time -((time_t)time)) * 1000000000)}},
NULL);
}
You need to include the header file which defines the type timespec. Either:
You forgot to include the header file or
You merely forward declared the type.
Second seems the most likely cause of error. Since you are creating an array, the compiler needs to know the definition of timespec as it needs to allocate that much memory for the array.
The problem is that struct timespec and nanosleep() are not defined in the C standard. They are provided by POSIX standard. It seems you are compiling with -std=c99 or so which makes your compiler to strictly adhere to the C99 standard and hence report errors. To be able to compile these POSIX constructs you will have to explicitly enable them.
Compilation with std=c99
Compilation after enabling POSIX definitions:
#if __STDC_VERSION__ >= 199901L
# define _XOPEN_SOURCE 600
#else
# define _XOPEN_SOURCE 500
#endif /* __STDC_VERSION__ */
#include <time.h>
int main()
{
double time = 0.1;
nanosleep((struct timespec[]) { {time, ((time - ((time_t)time)) *
1000000000)}}, NULL);
return 0;
}
__STDC_VERSION__ checks if the compiler you are using is c99 & depending on the compiler it enables the POSIX definitions.
_XOPEN_SOURCE defines which version of POSIX you want to refer to. Select the definition as per the POSIX version you use. 600 refers to POSIX 2004 while 500 refers to POSIX 1995.

undefined reference to `getline' in c

I am learning to use getline in C programming and tried the codes from http://crasseux.com/books/ctutorial/getline.html
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int atgc, char *argv[])
{
int bytes_read = 1;
int nbytes = 10;
char *my_string;
my_string = (char *)malloc(nbytes+1);
puts("Please enter a line of text");
bytes_read = getline(&my_string, &nbytes, stdin);
if (bytes_read == -1)
{
puts ("ERROR!");
}
else
{
puts ("You typed:");
puts (my_string);
}
return 0;
}
However, the problem is that the compiler keeps returning errors of this: undefined reference to 'getline'.
Could you please tell me what the problem is? Thank you!
I am using Win7 64bit + Eclipse Indigo + MinGW
The other answers have covered most of this, but there are several problems. First, getline() is not in the C standard library, but is a POSIX 2008 extension. Normally, it will be available with a POSIX-compatible compiler, as the macros _POSIX_C_SOURCE will be defined with the appropriate values. You possibly have an older compiler from before getline() was standardized, in which case this is a GNU extension, and you must #define _GNU_SOURCE before #include <stdio.h> to enable it, and must be using a GNU-compatible compiler, such as gcc.
Additionally, nbytes should have type size_t, not int. On my system, at least, these are of different size, with size_t being longer, and using an int* instead of a size_t* can have grave consequences (and also doesn't compile with default gcc settings). See the getline manual page (http://linux.die.net/man/3/getline) for details.
With that change made, your program compiles and runs fine on my system.
I am also using MinGW. I checked MinGW headers and getline() does not appear in any C header, it appears only in C++ headers. This means the C function getline() does not exist in MinGW.
getline isn't a standard function, you need to set a feature test macro to use it, according to my man page,
_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700
for glibc 2.10 or later,
_GNU_SOURCE
before that.

How to test if strdup() is available?

I'm using this:
#if !defined(_SVID_SOURCE) || !defined(_BSD_SOURCE) || _XOPEN_SOURCE < 500 || !(_XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED) \
|| _POSIX_C_SOURCE < 200809L
char * strdup(const char *s)
{
char *buffer = malloc(strlen(s) + 1);
if(buffer != NULL)
strcpy(buffer, s);
return buffer;
}
#endif
But is there the possibility to get a redeclaration error? Maybe into some gcc version or gcc-like compiler? I want to make it compatible with versions (standards) where there is no strdup(), -ansi, for example.
Also, how can I make it more portable?
This is absolutely the wrong use of feature test macros. Feature test macros are not defined by the implementation to tell the application what's available; they're defined by the application to request that the implementation provide conformance to (a particular version of) a particular standard.
The macros you should be using to test for a what the implementation supports are in unistd.h:
_POSIX_VERSION - version of POSIX supported. 200809L is latest.
_XOPEN_VERSION - version of X/Open Portability Guide, now called the "XSI" option of POSIX. Latest is 700 (from SUSv4). 600 (SUSv3) is common. 500 (SUSv2) is badly outdated.
_POSIX_THREADS - version of pthreads (should be the same as _POSIX_VERSION; mandatory since POSIX 2008)
...
Looking in the string.h on my platform (linux, gnu libc 2.16) I found :
#if defined __USE_SVID || defined __USE_BSD || defined __USE_XOPEN_EXTENDED \
|| defined __USE_XOPEN2K8
/* Duplicate S, returning an identical malloc'd string. */
extern char *strdup (const char *__s)
__THROW __attribute_malloc__ __nonnull ((1));
#endif
The #ifs are slightly different, I don't know the influence between those I found in my header and the ones your are using.
About the second question, you could use the autotools to create a config.h header describing the capabilities of the compiling platform, and use your own versions of missing functions.
In addition you could also use the gnulib "source library" which provides implementation of defective or missing functions (like strdup)
Using autotools should prevent any redeclaration error.
Yes, if it's already defined you will get redeclaration on strdup. The only way I know to get around this type of issue is to macro strdup to something else (say _strdup) and then define strdup with that other name. This is a little ugly but it gets the job done.
To your first question, no you can't determine if a function exists with the preprocessor. See this post.

Resources