5

I have a class that only has static members.

I would like to register one of its member functions (VerifyClean in the code below) to be called at exit, using the "atexit" library function.

The C++ FQA says that i must specify extern "C" for the function i want to register this way, like in the following example.

class Example { public: static void Initialize(); static void DoDirtyStuff {++dirtLevel;} static void CleanUpStuff {--dirtLevel;} private: static void VerifyClean(); // DOESN'T COMPILE: extern "C" static void VerifyClean(); static int dirtLevel; } int Example::dirtLevel; extern "C" void Example::VerifyClean() // DO I NEED extern "C" HERE? { assert(dirtLevel == 0); } void Example::Initialize() { dirtLevel = 0; atexit(&VerifyClean); } 

Do i really have to use extern "C"?

Does the answer change if i replace "atexit" with a non-library function (implemented in plain C)?

If the function VerifyClean were public and i decided to call it directly from C++ code, would i get link errors or runtime crashes? I ask this because the declaration doesn't mention extern "C" at all, so regular C++ code might handle the function call incorrectly. This works OK on my MS Visual Studio 2005 system.

8
  • 7
    Why have a class with only static functions? And the FQA is hardly a good place to learn about C++. Commented Nov 16, 2010 at 19:27
  • 6
    "FQA considered harmful" Commented Nov 16, 2010 at 19:31
  • 2
    The C++ FQA is a much more reliable resource for learning C++ than the FAQ. Commented Nov 16, 2010 at 19:33
  • 1
    Yes, it's a reliable resource for reading rants from one guy who likes whining about how C++ doesn't have garbage collection. Commented Nov 16, 2010 at 19:48
  • 4
    @John Millikin: If your goal is to learn diatribes about how C++ sucks, then I agree. If you actually want to learn to program, the FQA is a pile. Commented Nov 16, 2010 at 19:50

5 Answers 5

7

It is possible for a compiler to use different calling conventions for C and C++ code; however, in practice, this almost never occurs.

If you just want it to work and don't care about supporting obscure compilers, don't bother with extern "C". It's not necessary in any widely-used compiler.

If you want to be absolutely pedantic, or need to support a pedantic compiler, write a wrapper:

extern "C" static void ExampleVerifyClean() { Example::VerifyClean(); } void Example::Initialize() { dirtLevel = 0; atexit(&ExampleVerifyClean); } 
Sign up to request clarification or add additional context in comments.

2 Comments

+1. Explains that it's probably not worth worrying about (atexit(&VerifyClean) will probably work in practice), and then gives the picky technically correct solution.
Isn't extern "C" also required in case the C++ compiler has mangled the name of the function? Or do most C++ compilers avoid mangling when they don't have to (e.g. when there is no overloading or the functions aren't inside a class)?
1

link errors.

C++ performs what is called name mangling, which generates a link-time function name with type information.

extern C turns that off into a simpler identifier.

edit:

If everything is being compiled by a C++ compiler, it won't be an issue. But if you have an object file compiled by a C compiler and one being compiled by a C++ compiler, you are going to have some issues.

I seem to recall DLLs requiring an extern "C" specification, but that memory is maybe 10 years old at this point


Okay.

I whipped up a test case with a function that had a signature

int foo(float, float)

And compiled it under 3 different gcc invocations -

gcc test_c.c -S g++ test.cpp -S 

These two invocations produced different identifiers in the assembly. The C++ had mangled the name in its usual type-modifying approach. (of course compilers may do this differently)

Then, I wrapped foo in Extern "C" and invoked G++ again...

g++ test.cpp -S 

Which then removed the mangled C++ name, leaving a plain C unmangled name.

While there are other subtleties involved here, e.g., the order of arguments pushed onto the stack, I rest my case on this point, based on data.

9 Comments

The question has nothing to do with name mangling or linker errors; the problem is that compilers are allowed to use different calling conventions for C procedures and C++ static methods, so it's possible that code without extern will crash at runtime.
@John: the question does have to do with name mangling, and also the issue of possible calling convention that you mention. the purpose of name mangling is to have a sort of weak link time type checking (you can consider calling convention part of the type). some compilers complain even for code in the same compilation unit, although as far as I know for all extant such compilers the warning can be turned off. cheers,
@Paul: Yes, I know what name mangling is. But when you pass a function pointer to atexit(), you're not passing a name, you're passing an address. When you call the function pointer, name mangling is irrelevant because the name isn't even available. The only thing that matters is calling convention (stack/register, parameter order, etc).
@Alf: you don't even understand what's being argued about.
@Paul, what you've written is correct, but is not directly related to the question, which is using function pointers rather than the linker to achieve 'linkage'. (which has a very ambiguous title IMHO).
|
-1

Without extern "C", your function name will got mangled by compiler, so the function name might end up different from what you expect. You need to call the function using its mangled name (such as using GetProcAddress in windows) or you'll got linker error. Different compiler mangled it different way so it's best if you keep using extern keyword.

1 Comment

True, but using GetProcAddress (windows dll) we can call a function with mangled name IF we know what the mangled name is.
-1

you might use this :

class yourname { public: ... static void _cdecl AtExitCall (); }; int main() { ataexit( yourname::AtExitCall ); } 

Comments

-1

It is a mistake to use extern "c" in this case for 2 reasons:

  1. You use extern C, when you want to cross compile your program with a g++ (c++ compiler) for linking with gcc (C compiler). It tells g++ to turn off function name mangling. Clearly that is not your case here, or your whole file should be in extern "C"
  2. When using extern "C" you should use c-like function names, like Example_VerifyClean. Example::VerifyClean is not a valid c-function name and cannot be stored without mangling

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.