The extern "C" specifier disables C++ mangling, but that doesn't mean it disables mangling

The MSDN documentation on dllexport contains the following enigmatic paragraph, or at least did at the time I wrote this article:

dllexport of a C++ function will expose the function with C++ name mangling. If C++ name mangling is not desired, either use a .def file (EXPORTS keyword) or declare the function as extern "C".

I've seen this sentence misinterpreted as follows:

dllexport of a C++ function will expose the function with C++ name mangling. To disable name mangling either use a .def file (EXPORTS keyword) or declare the function as extern "C".

This is an understandable misinterpretation, but it is still a misinterpretation.

The root cause of the misinterpretation is that the author of this documentation was wearing C++-colored glasses. In the author's mind, there are only two interesting cases:

  1. C++ name mangling, where all the cool people are, and
  2. everything else, for all the lamers.

Here is a precise formulation of the paragraph:

dllexport of a C++ function will expose the function with C++ name mangling. If C++ name mangling is not desired, either use a .def file (EXPORTS keyword), which will expose the name without mangling, or declare the function as extern "C", which will expose the name with C mangling.

Here's a version of the paragraph that tries to take away the C++-colored glasses.

dllexport exposes the function as it is decorated by the compiler. For example, if the function is a C++ function, it will be exposed with C++ name mangling. If the function is a C function, or has been declared as extern "C", it will be exposed with C name mangling. To expose the function under its unmangled name (or to expose it via an alternate name), use use a .def file (EXPORTS keyword).

Behind the scenes: To forestall nitpickers, I had to go back to my copy of the C++ standard to make sure I filled in the blank in "The extern "C" _________" correctly. Officially, extern "C" is a storage class specifier.

Comments (18)
  1. Just to give the third method some love. There is a third method to export symbols, that is the linker's /export command line option. This can be put into a source file using the #pragma directive.

    #pragma comment(linker, "/export:symbol")

    But I'm only mentioning this because I think it is unfair that the MSDN documentaiton only mentions the .DEF file in the dllexport documentation.

  2. Joshua says:

    Private calling conventions in assembly make things interesting for the debugger.

  3. Aaron says:

    What is "C name mangling"?   I didn't know that C did anything to the names.

  4. Medinoc says:

    @Aaron: Mostly the number of bytes of parameters in __stdcall and __fastcall, but there's slightly more to it. Search __fastcall on MSDN and you should find the info.

  5. Adam Rosenfield says:

    @Aaron: Read the post linked to in the "C mangling" link in the third blockquote.  Each different calling convention has a slightly different name decoration in C.

  6. fatcathu says:

    Hmm.. IIRC WINAPI(_stdcall) are mangled, while all actuall Windows API dlls exports functions as non-mangled, so they all using DEF file ?

  7. Yuriy Gettya says:

    There's a third way to expose a function without any mangling:

    1. In .h file: extern "C" __declspec(dllexport) void foo();
    2. In .cpp/.c file: void foo(); // without __declspec(dllexport)!

    This way .def file is not needed

  8. Steve Friedl says:

    @Aaron - the C language itself doesn't provide for this, but an implementation might. Microsoft C compilers disambiguate the calling convention to avoid catastrophic stack corruption on mismatch.


  9. 640k says:

    Why is this even an issue 2012? The docs should have been super clear on this for the last 20 years.

    [We thought the docs were clear on this, especially since nobody asked about it until 2011. -Raymond]
  10. Joshua says:

    How does the linker figure it out at build time that the compiler exported symbol x@42 is the .def symbol x.

    I'm not sure this can happen but if it did I'd imagine it would be worse:




  11. foo says:

    @Yuriy. Maybe I'm missing something, but I don't see that using MSVC if I declare & define foo() as you suggest, except with __stdcall convention.

  12. @foo:

    I've got a .dll compiled with /Gd (__cdecl), here's how a function is prototyped and declared:

    extern "C" xENGINE_API HRESULT CreateInstance(shared_ptr<xFramework::IPlugin>& ppPlugin);

    HRESULT CreateInstance(shared_ptr<xFramework::IPlugin>& ppPlugin)

    ----- results of dumpbin:

       ordinal hint RVA      name

             1    0 00011398 CreateInstance = @ILT+915(_CreateInstance)

  13. Anonymous Coward says:

    I must say I initially also read the documentation as ‘extern "C" will disable name mangling’. Of course, when I tried to use the DLL I quickly discovered that this was not case. But I'm afraid it was easier to add ‘-Wl,--kill-at’ to the makefile than to have the added burden of a .def-file that must be kept in synch with the source files.

  14. Medinoc says:

    I remember I failed a school project because I assumed prefixing C symbols with an underscore was universal after seeing on both DOS (QuickC) and Windows (Visual and MinGW). I learned at my expense that *n*x systems don't add anything.

  15. foo says:

    @Yuriy: Ah right, so using extern "C" disabled C++ name mangling. Cool.

  16. David Walker says:

    Yes, I definitely understand the incorrect interpretation of the documentation.  It's hard to write good documentation!

    When I see something that says "if such and such is not desired, do this", I naturally assume that if I "do this", then "such and such" won't happen.

  17. Dave Bacher says:


    If you pop over to, and search on "Module Definition File," you'll find the format specs.

    However, basically, you do this:

    x=__x           @1

    x2=_x           @2

    x3=x            @3

    If you screw it up, the linker gives the usual suite of complaints -- General Protection Fault, Ambiguous Symbol, symbol not found, etc.

Comments are closed.

Skip to main content