static vs extern "C"/"C++"
Asked Answered
O

5

22

What is the difference between a static member function and an extern "C" linkage function ? For instance, when using "makecontext" in C++, I need to pass a pointer to function. Google recommends using extern "C" linkage for it, because "makecontext" is C. But I found out that using static works as well. Am I just lucky or...

class X {
   public:
   static void proxy(int i) {}
}
makecontext(..., (void (*)(void)) X::proxy, ...);

vs

extern "C" void proxy(int i) {}
makecontext(..., (void (*)(void)) proxy, ...);

EDIT: Can you show a compiler or architecture where the static member version does not work (and it's not a bug in the compiler) ?

Ostrom answered 26/2, 2009 at 19:58 Comment(3)
I am sorry, but I'm still not convinced ...of what? the fact that the Standard is more authoritatitive than the coincidental implementation-defined behaviour of some compilers?Alkane
This is an old post (8 years ago today) My point was at the time something like IMHO if every existing implementation differs from the standard then maybe you should ask a question of whether it is the standard that's wrong. I was looking for examples of platforms where it does not work.Ostrom
Fair enough. It's of course not unheard of for the C or C++ Standards to contain unintended consequences that all existing compilers ignore. This is my favourite at the moment: https://mcmap.net/q/18930/-does-accessing-a-declared-non-volatile-object-through-a-volatile-reference-pointer-confer-volatile-rules-upon-said-accesses But in this case, I think the Standard is quite clearly saying what it means, and implementations might change their behaviour at any moment if there is some advantage.Alkane
J
34

Yes, you are just lucky :) The extern "C" is one language linkage for the C language that every C++ compiler has to support, beside extern "C++" which is the default. Compilers may supports other language linkages. GCC for example supports extern "Java" which allows interfacing with java code (though that's quite cumbersome).

extern "C" tells the compiler that your function is callable by C code. That can, but not must, include the appropriate calling convention and the appropriate C language name mangling (sometimes called "decoration") among other things depending on the implementation. If you have a static member function, the calling convention for it is the one of your C++ compiler. Often they are the same as for the C compiler of that platform - so i said you are just lucky. If you have a C API and you pass a function pointer, better always put one to a function declared with extern "C" like

extern "C" void foo() { ... }

Even though the function pointer type does not contain the linkage specification but rather looks like

void(*)(void)

The linkage is an integral part of the type - you just can't express it directly without a typedef:

extern "C" typedef void(*extern_c_funptr_t)();

The Comeau C++ compiler, in strict mode, will emit an error for example if you try to assign the address of the extern "C" function of above to a (void(*)()), beause this is a pointer to a function with C++ linkage.

Johnsten answered 26/2, 2009 at 20:6 Comment(4)
To add to litb's answer, you should read about the calling conventions at Wikipedia - en.wikipedia.org/wiki/X86_calling_conventions. extern C implies cdecl calling convention; your compiler uses the same one for static member functions. Other compilers might as well choose any other.Krupp
Helltone, try it out comeaucomputing.com/tryitout it says: '"ComeauTest.c", line 4: error: a value of type "void ()() C" cannot be used to initialize an entity of type "void ()()"'Johnsten
however, it has a relaxxed mode in which it accepts the program. strict mode will try to adhere to the standard as much as possible.Johnsten
here is a doc with a detailed explanation about the function pointer with extern c.docs.oracle.com/cd/E19059-01/wrkshp50/805-4956/bajdcjch/…Tellurate
T
5

Note, that extern C is the recommended way of C/C++ interoperability. Here is the master talking about it. To add to eduffy's answer: note that static functions and variables in the global namespace are deprecated. Use an anonymous namespace at least.

Back to extern C: if you don't use extern C you will have to know the exact mangled name and use it. That is much more of a pain.

Thousandfold answered 26/2, 2009 at 20:7 Comment(1)
Note: the OP was talking about static methods ("member functions"), not global functions with static linkage.Bigot
W
4

extern "C" disables the C++ compiler's name mangling (which is required for overloading).

If you declare a function in A.cpp to be static, then it cannot be found by B.cpp (it's leftover from C, and it has the same effect of putting a function inside an anonymous namespace).

Wages answered 26/2, 2009 at 20:2 Comment(3)
This does not answer my questionOstrom
It can also change the calling convention.Dishcloth
Note: the OP was talking about static methods ("member functions"), not global functions with static linkage.Bigot
P
2

Most of what extern "C" does is largely compiler dependant. Many platforms change the name mangling and calling convention based off the declaration, but none of that is specified by the standard. Really the only thing the standard requires is that the code in the block is callable from C functions. As for your specific question, the standard says:

Two function types with different language linkages are distinct types even if they are otherwise identical.

This means extern "C" void proxy(int i) {} and /*extern "C++"*/void proxy(int i) {} have different types, and as a result pointers to these functions would have different types as well. The compiler doesn't fail your code for the same reason it wouldn't fail a great piece of work like:

int *foo = (int*)50;
makecontext(..., (void (*)(void)) foo, ...);

This code might work on some platform, but that doesn't mean it will work on another platform (even if the compiler was fully standard compliant). You are taking advantage of how your particular platform works, which might be ok if you aren't concerned about writing portable code.

As for static member functions, they aren't required to have a this pointer so the compiler is free to treat them as a non member function. Again, the behavior here is platform specific.

Polyglot answered 26/2, 2009 at 20:26 Comment(1)
Good answer, but you totally miss the point of my question. My question concerns the difference between extern "C" function and a static member function.Ostrom
D
2

Generally speaking

Storage classes:

storage classes are used to indicate duration and scope of a variable or identifier.

Duration:

Duration indicates the life span of a variable.

Scope:

Scope indicates the visibility of the variable.

Static storage class:

The static storage class is used to declare an identifier that is a local variable either to a function or a file and that exists and retains its value after control passes from where it was declared. This storage class has a duration that is permanent. A variable declared of this class retains its value from one call of the function to the next. The scope is local. A variable is known only by the function it is declared within or if declared globally in a file, it is known or seen only by the functions within that file. This storage class guarantees that declaration of the variable also initializes the variable to zero or all bits off.

Extern storage class:

The extern storage class is used to declare a global variable that will be known to the functions in a file and capable of being known to all functions in a program. This storage class has a duration that is permanent. Any variable of this class retains its value until changed by another assignment. The scope is global. A variable can be known or seen by all functions within a program.

Dosia answered 6/8, 2013 at 9:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.