Is there any way, short of putting an attribute on each function prototype, to let gcc know that C functions can never propagate exceptions, i.e. that all functions declared inside extern "C"
should be __attribute__((nothrow))
? Ideal would be a -f
style command line option.

- 208,859
- 35
- 376
- 711
-
there is -fnothrow-opt, but I don't think it will work the way you want. Check http://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Dialect-Options.html#C_002b_002b-Dialect-Options for more information – Himanshu Jan 14 '11 at 20:58
-
Isn't a fairly common response to this kind of thing to define THIS_LINKAGE, THAT_ATTRIBUTES, THE_OTHER_DECORATION macros, and hide the rubbish in there? It still unnecessarily messes up your code when read as C if no such macros are there already, but by a controlled amount. – Steve Jessop Jan 14 '11 at 23:20
-
2Also, is it in point of fact true that `extern "C"` functions can't throw exceptions (with defined behavior)? If so you'd want GCC to make the optimization without an option. But it might not be, if the function was declared `extern "C"` but (unlike your code) implemented in C++, I suppose in practice it can throw exceptions as long as it isn't actually called from C. Can't remember if that's legal or not. – Steve Jessop Jan 14 '11 at 23:27
-
I'm one of the stubborn few who is ardently against that sort of mess, mainly because I'm always running into subtle problems with software and have to track down WTF these things are all defined as. It also makes it a lot harder to keep your code modular, since everything ends up depending on a central header that defines all this junk, and you can't easily pull out just one module and use it alone. – R.. GitHub STOP HELPING ICE Jan 14 '11 at 23:28
-
5@Steve: Here we run into a difference between C and "GNU C". C has no such thing as exceptions, and no reasonable C++ program can expect exceptions to propagate across foreign function (C) boundaries, even if the function makes a callback to potentially-C++ code (like in the case of `qsort`). However, the gcc developers want to exceptions to be part of C (they can be part of "GNU C" with `-fexceptions`) and want to support exceptions across C/C++ code boundaries in the case of callbacks and such. Thus the mess we're in. – R.. GitHub STOP HELPING ICE Jan 14 '11 at 23:31
-
1@R..: gotcha, thanks. Btw in this case you could put `#ifndef THAT_ATTRIBUTES #ifdef __cplusplus #define THAT_ATTRIBUTES __attribute__((nothrow)) #else #define THAT_ATTRIBUTES` at the start of every header, to avoid the dependency on `common_junk.h`. I sympathise with your anti-junk stance, though, it's much nicer to write proper C and expect implementations to do something reasonable with it. – Steve Jessop Jan 14 '11 at 23:32
-
@Radek S: Thanks for putting a bounty on this! – R.. GitHub STOP HELPING ICE Feb 06 '11 at 00:49
4 Answers
You can always use -fno-exceptions
which will ensure that the c++ compiler does not generate exception propagation code.

- 27,972
- 12
- 65
- 103
-
1I'm asking my question from a standpoint of writing library code in C which might be called from C++. I really don't want to fill my headers with gcc-specific or C++-specific mess to help gcc optimize C++ callers that call my code; I'd much rather just document that if you're calling it from C++ and don't want unnecessary exception overhead, you should pass such-and-such option to g++. If there is no such option, I'll just be content to let g++ generate bloated code. – R.. GitHub STOP HELPING ICE Jan 14 '11 at 22:01
-
9Are you sure you're actually optimizing something real? Nowadays exception handling setup is optimized to only take CPU time when an exception *is* thrown (the uncommon case) rather than when it isn't (the common case). So there is nothing really to save in the common case. And if the caller really cares about the exception overhead, then this answer is the right one; turn off exceptions entirely for any code that needs to be fast. – apenwarr Feb 03 '11 at 10:50
-
1I would agree that the time cost of supporting exceptions is zero on many modern systems, but the space cost (in terms of executable/library size on disk) is huge. – R.. GitHub STOP HELPING ICE Feb 04 '11 at 20:25
-
2Define huge because I think you're grasping at straws. Unless you are working in the embedded space this shouldn't matter. – John Bellone Feb 12 '11 at 15:01
-
1R.. is correct; if you want to see the space cost for yourself, compile a test program where you define a local variable with a non-trivial destructor and then call `puts()`. Even at -O3, GCC 4.8 refuses to generate the obvious straight-line code; it will always generate an extra (dead) codepath that ends with a call to `_Unwind_Resume`. Imagine one of those extra dead blocks for every scope in your program, and you'll begin to grasp the size of the problem... even on a desktop system. (The filesize of the executable is one issue. Icache pollution is the other.) – Quuxplusone Jun 25 '14 at 20:14
Side note:
Are you sure telling the compiler "all these funcs never throw" is exactly what you want ?
It's not necessarily so that extern "C" ...
functions cannot propagate/trigger exceptions. Take a case in point:
class Foo {
public:
class Away {};
static void throwaway(void) { throw Away(); }
}
extern "C" {
void wrap_a_call(void (*wrapped)(void)) { wrapped(); }
}
int main(int argc, char **argv)
{
wrap_a_call(Foo::throwaway);
return 0;
}
Compiling and running this creates a C-linkage function wrap_a_call()
which, when called like above, will happily cause an exception:
$ ./test
terminate called after throwing an instance of 'Foo::Away'
Abort(coredump)
I.e. there can be "exception leakage" with extern "C"
(through invoking function pointers) and just because you're using/invoking extern "C"
functions in a particular place in C++ doesn't guarantee no exceptions can be thrown when invoking those.

- 17,675
- 3
- 44
- 63
-
1Yes. Unless a C function is specified to interact with and support propagation of C++ exceptions (which, since it can't catch them, means it just has no memory leak issues or internal state that could be damaged by `longjmp`ing out of it), propagating an exception across C++-to-C-to-C++ call/callback boundaries is already dangerous (and for functions in the C standard library, it's undefined behavior). – R.. GitHub STOP HELPING ICE Jan 23 '12 at 16:30
When exception is raised it generate interrupt which unroll stack and override existing stack. It goes up to the point where try/except syntax is. This mean than you do not have any overhead if you do not use exceptions. Only overhead in memory/time is at try/catch blocks and stack unrolling at throw().
If your c functions does not generate exceptions your overhead will be only in space when you will call try/catch in your C++ but is same for any number of exceptions. (and small time overhead on initialising this small space whit constant).

- 10,336
- 3
- 34
- 56
GCC 4.5 seems to optimize those out for me automatically. Indeed, this line appears in the list of changes at http://gcc.gnu.org/gcc-4.5/changes.html :
- GCC now optimize exception handling code. In particular cleanup regions that are proved to not have any effect are optimized out.

- 4,964
- 1
- 26
- 33
-
It optimizes out unnecessary code, but does it optimize out unnecessary DWARF unwind information? – R.. GitHub STOP HELPING ICE Feb 16 '11 at 19:28
-
I thought it did in general for C functions yes, but I checked again more carefully and it only appears to do it in the case of _inline_ functions.. – Samuel Audet Feb 18 '11 at 03:50