33

I've got C++ functions that I want to declare using extern "C" even though they are only called in C++ code. Yes, I know this is strange but it's something I would like to do for consistency since we have mixed C and C++ declarations. I just want to make sure that declaring a C++ function as extern "C" won't affect the behavior of throwing.

It would look something like this:

extern "C" void foo() {throw exception;}

int bar()
{
    try
    {
        foo();
    } catch (exception e) { return 1; }
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Will Brode
  • 1,026
  • 2
  • 10
  • 27
  • [Related question](http://stackoverflow.com/questions/4695741/is-there-a-gcc-option-to-assume-all-extern-c-functions-cannot-propagate-except). – Alexey Frunze Apr 06 '13 at 00:38
  • 1
    The answers assert that you're invoking undefined behaviour if an exception is thrown from C++ code into actual C code (which would not know what to do with an exception). I think that's correct, but are you asking about calling the `extern "C"` functions from C++ or from C? If you're calling them from C++ (and never from C), there's the inevitable question "why are the functions `extern "C"` if they're never called from another language?", but I think that simply calling C++ functions with `extern "C"` from C++ means there is no language boundary crossed and therefore no undefined behaviour. – Jonathan Leffler Apr 06 '13 at 00:49
  • Thanks to everyone who contributed to answering this. If I understand correctly, the ultimate answer to my question was this: extern "C" does not change the way an exception is handled. However, throwing an exception that is not caught and crosses language boundaries has undefined behavior. – Will Brode Apr 09 '13 at 18:05
  • q:"extern "C" does not change the way an exception is handled" -- I do not read the answers that way. Specifically `/EHsc` says otherwise. – Martin Ba Aug 01 '14 at 19:48
  • @JonathanLeffler every compiler version of cpp is another language. If you have a msvc static library it will not work with GCC unless it was a C library using extern "C". Every compiler is allowed to mangle names how they feel, so you end up with undefined references when the reference actually exists. I think and don't see any reason why name mangling shouldn't be standardized; but this is a common reason for using extern "C" for C++ only. Example, I must create dll to use code from msvc in gcc as the code requires msvc specific stuff. Then I must use extern "C" to suppress name mangling. – user13947194 Aug 31 '21 at 06:21

4 Answers4

17

"Can C++ functions marked as Extern “C” throw?"

Yes, in the sense that neither the language nor the compiler will prevent you from doing so.

No, in the sense that if you throw, it would be an undefined behaviour, as the C++ exception crosses language boundaries.

In practice: do not do it. Catch the exception and translate it into an error code, or a means the other language can understand.

So the bottomline is: do NOT throw exception from functions marked as extern "C".

Nawaz
  • 353,942
  • 115
  • 666
  • 851
Nathan Ernst
  • 4,540
  • 25
  • 38
  • It may technically be "unspecified behavior", but either way: not good. – Nathan Ernst Apr 06 '13 at 00:45
  • Does the C++ standard really say that it's undefined behavior when an exception crosses language boundaries? I have a hard time believing that, as the C++ standard deals with C++ and C++ only, and "language boundaries" is outside the scope of C++. I would assume that if a C++ exception is thrown into a language that doesn't support C++ exceptions, the exception is just propagated until either it is caught somewhere or the program is terminated. But of course it depends on the operating system and compiler. – user1610015 Apr 06 '13 at 01:34
  • 5
    You can't say `YES` when its `undefined behavior`. When you invoke `undefined behavior` your code is basically broken. – Martin York Apr 06 '13 at 03:44
  • 4
    @LokiAstari, the question was asked can they throw, and the answer is yes. If an extern "C" function was invoked directly from a function with c++ linkage, there is no undefined behavior. Same function invoked from C, undefined behavior. There isn't necessarily a language cross just because of linkage, but it is certainly a smell. – Nathan Ernst Apr 08 '13 at 23:48
  • 2
    @LokiAstari, I must take exception with your statement, "You can't say `YES` when its `undefined behaviour`." "Undefined behavior" is immaterial to whether or it can or should happen. It only specifies that the result is undefined. It does not specify that it can never occur. Exceptions crossing boundaries happens all the time. C++->C; C++->Java; C++->Python. The difference is, most language translation library provide a facility to catch, translate, and rethrow exceptions into the target language. – Nathan Ernst Apr 09 '13 at 01:19
  • Can you increment a variable twice in an expression. Yes. But its undefined behavior and thus has no meaning. You can't say YES and then say its undefined behavior. Because its undefined behavior it means that its not a valid operation. – Martin York Apr 09 '13 at 09:22
  • 2
    Your first assumption is wrong: `If an extern "C" function was invoked directly from a function with c++ linkage`. If it throws its undefined behavior. The ABI for a C function does not contain the information needed to allow stack unrolling. – Martin York Apr 09 '13 at 09:23
  • 4
    I have to agree with @LokiAstari. In my code, I have C++ calling a `extern c` function that throws an exception, and it is *not being caught* (even with `catch(...)`). Compiler is Intel compiler (icpc). All code is written in C++, there is no C. The linkage difference seems to be enough to break the stack unrolling. – Mark Lakata Apr 28 '15 at 21:52
  • 1. The C++ standard give zero mention to COM: COM is a Microsft API. – Nathan Ernst Apr 30 '15 at 03:50
  • 1
    I stand by my original assertion. There will obviously be changes to accommodate a compiler that has either an option to not throw or handle the case when code does throw. – Nathan Ernst Apr 30 '15 at 03:57
  • Martin York (above) said that the ABI for a C function does not contain the information needed to allow stack unrolling. That is, however, not something defined by either the C or C++ standards. It so happens, for instance, that on Windows, C++ exceptions are built on top of SEH, which is a C extension and which allows C functions to participate fully in exception handling. It's quite likely that similar features exist on some other platforms too (though I can't think of any OTOH). – al45tair Mar 19 '19 at 11:02
8

For GCC the answer seems inconclusive.

The MSVC documentation, however is relatively clear on the subject:

  • /EHa and /EHs ... tells the compiler to assume that functions declared as extern "C" may throw an exception.
  • /EHsc ... tells the compiler to assume that functions declared as extern "C" never throw a C++ exception

So for Visual-C++ it depends on the compiler options whether you get defined behavior.

Community
  • 1
  • 1
Martin Ba
  • 37,187
  • 33
  • 183
  • 337
  • 1
    +1, but you missed the gcc answer in one of the linked comments: `-fexceptions`. From the gcc docs: "...you may need to enable this option when compiling C code that needs to interoperate properly with exception handlers written in C++". – EML Jan 07 '16 at 17:28
2

it will compile but it is undefined behavior to throw from function marked as having C linkage. C doesn't have exceptions, therefore in general you should just return an error code and/or provide a function that returns the information about the last error.

#include <exception>
extern "C" void foo() {throw std::exception();}

compiles well

4pie0
  • 29,204
  • 9
  • 82
  • 118
1

Here is answer for your question: http://yosefk.com/c++fqa/mixing.html#fqa-32.6

Basically you won't be able to catch it. (but why you won't just compile it and try? :))

Piotr Jaszkowski
  • 1,150
  • 9
  • 12
  • 20
    "compile it and try" is never a good idea for languages with undefined behavior. – Cody Gray - on strike Apr 06 '13 at 00:42
  • 4
    But it might lead you to make false assumptions about the behaviour of the code when in fact you shouldn't assume anything at all, because it's undefined and a compiler could do anything with it. – Scott Olson Apr 06 '13 at 00:54
  • 5
    @PiotrJaszkowski: It may not destroy the universe but dragons will spew out your nose. Trying `undefined behavior` is pointless you don't learn anything as the test has no meaning. – Martin York Apr 06 '13 at 03:47