I tried googling it but all results were about C++'s throw std::exception().
I was reading through libraries (was curious how stuff like printf, malloc and FILE were implemented) and came across the definition for the malloc function:
extern void *malloc (size_t __size) __THROW __attribute_malloc__
__attribute_alloc_size__ ((1)) __wur;
When using the IDE (Visual Studio Code) to trace back to definitions for each thing, __THROW led to this:
# if !defined __cplusplus && __GNUC_PREREQ (3, 3)
// stuff that doesn't happen
# else
# if defined __cplusplus && __GNUC_PREREQ (2,8)
# define __THROW throw ()
# define __THROWNL throw ()
# define __NTH(fct) __LEAF_ATTR fct throw ()
# define __NTHNL(fct) fct throw ()
// continuation to the if-else macro
This confused me, as, as far as i know, c doesn't have exceptions and instead uses int error codes. Even more, why are there parentheses as in a function call?
What does it mean and what does it do in the presented case?
There is no throw keyword in C. That's a C++ thing.
As to why you find it in your code, the clue is right here in the preprocessor macros:
# if !defined __cplusplus && __GNUC_PREREQ (3, 3)
// stuff that doesn't happen
# else
# if defined __cplusplus && __GNUC_PREREQ (2,8)
# define __THROW throw ()
# define __THROWNL throw ()
# define __NTH(fct) __LEAF_ATTR fct throw ()
# define __NTHNL(fct) fct throw ()
// continuation to the if-else macro
This code is written so it will compile with either a C or C++ compiler. The C++ bit that references throw and other C++isms will only be compiled if a C++ compiler is used, as such a compiler will define the __cplusplus macro.
When you compile it with a C compiler, only the bit marked // stuff that doesn't happen will be used, not the else block.
The C 2017 standard doesn't define a throw keyword. The header file may be used by both C and C++ compilers and as #Barmar noted it doesn't apply to C (in C++, btw, throw() specifier means that the function doesn't throw exceptions).
There is no throw keyword in C. In C, the source text throw is an ordinary identifier.
The macro __THROW you show is replaced by nothing (an empty sequence of preprocessor tokens) when compiling in C, because the compilers the code you show is targeted for define __cplusplus only when compiling as C++, not when compiling as C. So, in C, !defined __cplusplus_ is true, and the // stuff that doesn't happen happens. You do not show that code, but it likely contains #define __THROW or equivalent, defining __THROW to be replaced by the empty sequence.
If you see other statements being used, where __THROW is defined to be replaced by throw (), then you are compiling in C++ mode, not 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.
I have the following C program:
#include <sys/stat.h>
int main(int argc, char **argv) {
struct stat fileStat;
if(stat(argv[1],&fileStat) < 0)
return 1;
}
When I compile it to LLVM IR using Clang, I can see that stat is declared as following:
declare i32 #stat(i8*, %struct.stat*)
Usually, such an external call to a system function directly maps to a C standard library function. For example, I can find malloc with the following:
nm -D /lib/x86_64-linux-gnu/libc.so.6 | grep malloc
However, the stat function seems to be treated differently. When grepping for stat, I can find related functions such as __xstat but not the stat function itself.
When I trace the call to the external library with ltrace I see the following call: __xstat(1, ".", 0x7fff7928c6f0). Also the code in the executable confirms that instead of calling the stat function the __xstat function is called.
I did not observe other function calls to the C standard library that have other names than those declared in the C program. Why is there no direct equivalent in the standard library and how does my compiler find out that it should produce a call to __xstat and not to stat?
Header sys/stat.h defines stat as a macro that calls __xstat in glibc:
#define stat(fname, buf) __xstat (_STAT_VER, fname, buf)
I found the following comment in /usr/include/x86_64-linux-gnu/sys/stat.h:
/* To allow the `struct stat' structure and the file type `mode_t'
bits to vary without changing shared library major version number,
the `stat' family of functions and `mknod' are in fact inline
wrappers around calls to `xstat', `fxstat', `lxstat', and `xmknod',
which all take a leading version-number argument designating the
data structure and bits used. <bits/stat.h> defines _STAT_VER with
the version number corresponding to `struct stat' as defined in
that file; and _MKNOD_VER with the version number corresponding to
the S_IF* macros defined therein. It is arranged that when not
inlined these function are always statically linked; that way a
dynamically-linked executable always encodes the version number
corresponding to the data structures it uses, so the `x' functions
in the shared library can adapt without needing to recompile all
callers. */
# ifdef __REDIRECT_NTH
extern int __REDIRECT_NTH (stat, (const char *__restrict __file,
struct stat *__restrict __buf), stat64)
__nonnull ((1, 2));
# endif
__REDIRECT_NTH is defined in /usr/include/x86_64-linux-gnu/sys/cdefs.h:
/* __asm__ ("xyz") is used throughout the headers to rename functions
at the assembly language level. This is wrapped by the __REDIRECT
macro, in order to support compilers that can do this some other
way. When compilers don't support asm-names at all, we have to do
preprocessor tricks instead (which don't have exactly the right
semantics, but it's the best we can do).
Example:
int __REDIRECT(setpgrp, (__pid_t pid, __pid_t pgrp), setpgid); */
#if defined __GNUC__ && __GNUC__ >= 2
# define __REDIRECT(name, proto, alias) name proto __asm__ (__ASMNAME (#alias))
# ifdef __cplusplus
# define __REDIRECT_NTH(name, proto, alias) \
name proto __THROW __asm__ (__ASMNAME (#alias))
# define __REDIRECT_NTHNL(name, proto, alias) \
name proto __THROWNL __asm__ (__ASMNAME (#alias))
# else
# define __REDIRECT_NTH(name, proto, alias) \
name proto __asm__ (__ASMNAME (#alias)) __THROW
# define __REDIRECT_NTHNL(name, proto, alias) \
name proto __asm__ (__ASMNAME (#alias)) __THROWNL
# endif
# define __ASMNAME(cname) __ASMNAME2 (__USER_LABEL_PREFIX__, cname)
# define __ASMNAME2(prefix, cname) __STRING (prefix) cname
From the comments and macro definitions it seems that the alias is specified in inline assembler.
I have functions which abstract serial- and socket IO (Linux / Windows) implemented in C.
All of them are marked as extern "C" because they may get called from C++ as well.
Is it safe to use __attribute__((__nothrow__)) (or MinGW Macro __MINGW_NOTHROW) here / can i assume no exceptions are thrown?
Called functions - Sockets:
(not all additions for WinSock listed)
socket
connect
send / recv
close (closesocket on Windows)
sendto / recvfrom
Called functions - Serial:
Since serial IO code differs to much between windows / linux not all are listed here
Linux (GNU)
open
tcgetattr
read / write
close
Windows (MinGW)
CreateFile
GetCommState / SetCommTimeouts
ReadFile / WriteFile
CloseHandle
Since ANSI C has no exceptions (please correct me if I'm wrong) they won't be thrown, but how about GCC extensions and OS API calls?
Documentation: http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html (see nothrow).
C
GNU C (Linux) uses __THROW macro instead of __MINGW_NOTHROW.
While the MinGW one is __nothrow__ attribute only, __THROW contains __leaf__ attribute too.
C++
If you use C++, __THROW has another meaning: throw() - indicating that no exception is thrown (analog to __nothrow__; but defined in the C++ standard).
So it depends on whether you compile with C or C++, not on what you call the functions from (GNU C / C++ only!).
Example:
void f() __THROW;
Treated as ...
GNU C:
void f() __attribute__((__nothrow__, __leaf__))
GNU C++:
void f() throw()
Functions1) which are cancellation points, therefore not marked with
__THROW:
open()
read()
write()
close()
connect()
send()
recv()
close()
sendto()
recvfrom()
Functions1) marked with __THROW:
tcgetattr()
socket()
At least, these are save to __nothrow__.
In contrast, MinGW doesn't differ C from C++; in both cases the attribute is set.
Using example from above, __nothrow__ is set on C and C++:
void f() __attribute((__nothrow__))
Functions1) not marked with __MINGW_NOTHROW:
socket()
connect()
send()
recv()
closesocket()
sendto()
recvfrom()
CreateFile()
GetCommState()
SetCommTimeouts()
ReadFile()
WriteFile()
CloseHandle()
To make it short: none!
Compatibility
With C
C language code that is expecting to interoperate with C++ should be
compiled with -fexceptions. This will make debugging a C language
function called as part of C++-induced stack unwinding possible.
In particular, unwinding into a frame with no exception handling data
will cause a runtime abort. If the unwinder runs out of unwind info
before it finds a handler, std::terminate() is called.
Please note that most development environments should take care of
getting these details right. For GNU systems, all appropriate parts of
the GNU C library are already compiled with -fexceptions.
( source: http://gcc.gnu.org/onlinedocs/libstdc++/manual/using_exceptions.html )
So compiling with -fexceptions and there's no need for equivalent attribute. If you only can mark specific functions you have to / should use __nothrow__.
But while using __nothrow__ attribute looks save only on GNU C++, and some functions of GNU C on Linux, it's not that clear on Windows.
Addendum:
To avoid some parts of this problem, i've written a macro similar to __THROW but usable on MinGW too:
#if defined __GNUC__
#ifndef __THROW
#ifdef __cplusplus
#define __THROW throw()
#else
#define __THROW __attribute__((__nothrow__))
#endif
#endif
#else
#define __THROW
#endif
Note: __leaf__ is not included.
1) Talking only about those which are listed on my question.
take care of gcc version, nothrow has been introduced with gcc 3.3!
you can port __THROW from sys/cdefs.h to mingw:
/* skip this entire part on linux (= glibc available)*/
#if defined __GNUC__ && !defined __linux__
/********* port __GNUC_PREREQ macro to mingw *********/
# if !defined __GNUC_PREREQ
# if !defined __MINGW_H
# include <_mingw.h>
# define __GNUC_PREREQ(major, minor) __MINGW_GNUC_PREREQ(major, minor)
# else
# if defined (__GNUC_MINOR__)
# define __GNUC_PREREQ(major, minor) __GNUC__ > (major) || (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)))
# else
# define __GNUC_PREREQ(major, minor) 0
# endif
# endif
#endif /* __GNUC_PREREQ */
/********* from gnu c blirary *********/
/* All functions, except those with callbacks or those that
synchronize memory, are leaf functions. */
# if __GNUC_PREREQ (4, 6) && !defined _LIBC
# define __LEAF , __leaf__
# define __LEAF_ATTR __attribute__ ((__leaf__))
# else
# define __LEAF
# define __LEAF_ATTR
# endif
/* GCC can always grok prototypes. For C++ programs we add throw()
to help it optimize the function calls. But this works only with
gcc 2.8.x and egcs. For gcc 3.2 and up we even mark C functions
as non-throwing using a function attribute since programs can use
the -fexceptions options for C code as well. */
# if !defined __cplusplus && __GNUC_PREREQ (3, 3)
# define __THROW __attribute__ ((__nothrow__ __LEAF))
# define __THROWNL __attribute__ ((__nothrow__))
# define __NTH(fct) __attribute__ ((__nothrow__ __LEAF)) fct
# else
# if defined __cplusplus && __GNUC_PREREQ (2,8)
# define __THROW throw ()
# define __THROWNL throw ()
# define __NTH(fct) __LEAF_ATTR fct throw ()
# else
# define __THROW
# define __THROWNL
# define __NTH(fct) fct
# endif
# endif
#else /* Not GCC. */
# define __inline /* No inline functions. */
# define __THROW
# define __THROWNL
# define __NTH(fct) fct
#endif /* GCC. */
see glibc - sys/cdefs.h for full code.
edit: __GNUC_PREREQ can be replaced with __MINGW_GNUC_PREREQ(major, minor), then you don't have to redifine it as above.