What will happen if I "shorten" this call:
GetInstanceOfClass1()->GetInstanceOfClass2();
(where the instance of Class2 is a member of Class1) with a extern function declared in Class1.cpp:
extern void GetInstanceOfClass2()
{
GetInstanceOfClass1()->GetInstanceOfClass2();
}
Will the compiler (clang) produce inefficient code? Is that an ugly, bad idea actually?
Related
The following C++ code compiles with Visual C++ and g++:
struct S
{
static void foo();
};
extern "C"
void S::foo() {}
struct T
{
static void foo();
};
extern "C"
void T::foo() {}
auto main() -> int
{
S().foo();
T().foo();
}
Is it valid?
If it's valid, since the implementation may be in a separate translation unit, does that imply that a static member function always has the same calling convention as a C function (and if not, how does it not imply that)?
C++11 7.5/4 "Linkage specifications"
A C language linkage is ignored in determining the language linkage of
the names of class members and the function type of class member
functions.
So your example is valid in the sense that it's not malformed or an error, but the extern "C" should have no effect on S::foo() or T::foo().
A static member function has the same calling convention as a C function. But, name mangling applies. So, even if you get away with declaring your static member as extern "C", the linker would probably not find it when you try to link it against the C code that calls that function.
What you can easily do is declare a wrapper/stub that calls the static member from a plain function. Also, you can assign the static member function's address to a plain function pointer.
No it is ignored, the problem is name mangling (function naming for linkage phase). So the trick is to define a C function and use your C++ static method as a stub to call it, like this:
struct S
{
static void foo();
};
extern "C" void S_foo_impl();
void S::foo() { S_foo_impl(); }
auto main() -> int
{
S::foo();
}
Of course, S_foo_impl should be defined in a external C module.
Let's say I have a C++ header file foo.hpp:
namespace foo {
int bar(int);
}
I cannot use extern "C" because it needs to only be accessible from the namespace foo.
Is there a portable (or relatively portable) way to declare foo::bar in a C file foo.c so that it will link with anyone using foo::bar from C++?
I know that on a particular system with a particular compiler, I can just find out how foo::bar is mangled and do something like this in foo.c:
int ZN3foo3barEi(int x) { /* ... */ }
But this is neither portable nor readable.
extern "C" can be nested (in fact, that's how headers like <cstdio> typically work!), so you can just do the following:
/* C++ code */
namespace foo {
extern "C" {
int bar(int);
}
}
After that, you just implement it in C as usual:
/* C code */
int bar(int x) {
return -x; /* or whatever */
}
Unfortunately, if there's a naming conflict (say, if you have both foo::bar and baz::bar), you won't be able to have them both, unless they're the same function.
Would a wrapper be acceptable?
namespace foo {
int bar(int);
}
extern "C" int callable_from_c(int f) {
return foo::bar(f);
}
You are forced to your backup plan (to use a wrapper function) for the following reason: C++ supports overloading of functions, and by that reason you can have different implementations of bar (with different fingerprints, even compatible) while you can have only one implementation in C. Which of the C++ possibilities would be matched for bar in case you call them from C? What if you have bar(int) and bar(long) in C++ and you want to call bar(3) from C?
The solution is to have one wrapper extern "C" function that calls the appropiate non-C function. This function can be called from C and you'll get the desired results.
If you look, for example, at the identifier names that the linker manages, you'll see how the compiler mangles identifiers to cope at linking time with overloading. That does not happen if you declare a function extern "C" in C++.
Another reason is that you don't have namespaces in C. The C function version must be visible at the global namespace level. You are not able to hide a C calling convention inside a namespace because it is callable from all the C code or you'll be violating the C calling conventions.
Isn't the extern keyword supposed to simply 'blind' the compiler? Here are the codes that i can't understand why it is without an error.
struct A {
int a;
};
class B {
static A x;
public:
void f() { x.a=0; }
};
extern A B::x; // not allocated.
main() {
B z;
z.f();
}
As you already know, the static member should be instantiated manually. However, i added the extern keyword, which means it's not actually allocated. It is very weird that it compiles fine!
There is no such thing as an extern declaration for static member variables! The variable is declared extern anyway based on the definition of the class. gcc warns that you can't explicitly declare a static member variable to be extern. However, both gcc and clang compile and link the code without further ado, clearly ignoring the extern.
Of course, with the above code it is also clear that you are compiling with some non-standard mode in the first place as main() relies on the implicit int rule which was never part of C++.
I'm trying to call a kernel wrapper foo from a C++ class. I've tried to do as suggested here below:
// In CPP.h:
class cls {
extern "C" inline void foo();
}
// In Kernels.cu:
#include "CPP.h"
extern "C" inline void cls::foo() {
// call kernels here
}
but this has not worked - I get a compiler errors:
CPP.h: invalid storage class for a class member
CPP.h: "cls::foo" was referenced but not defined
Kernels.cu: label "cls" was declared but never referenced
What's going wrong?
You shouldn't mark a class method with extern "C".
Make a wrapper non-member function with extern "C" specifier, and let this function call your class's method (you will need to specify an instance also).
Sorry guys I know my english is bad, but i made examples so that my question is more clearer.
a.cpp
#include <iostream>
using namespace std;
void funcfoo(){
cout << "test only" << endl;
}
int varfoo = 10;
b.cpp
#include <iostream>
using namespace std;
extern void funcfoo();
extern int varfoo;
int main(){
funcfoo();
cout << varfoo;
return 0;
}
Then I compile it like this "cl b.cpp a.cpp"
My question is. How come when I remove the "extern keyword before void funcfoo()" it works fine, but when i remove the extern keyword
before int var foo I get an error?
The issue is what each one of the lines of code means. int varfoo is a definition of a variable, while void funcfoo() is only a declaration. You can provide multiple declarations of an entity, but only one definition. The syntax to provide a declaration and only a declaration of a variable is by adding the extern keyword: extern int varfoo; is a declaration
3.1 [basic.def]/2 A declaration is a definition unless it declares a function without specifying the function’s body (8.4), it contains the extern specifier (7.1.1) or a linkage-specification25 (7.5) and neither an initializer nor a function body [...]
When you remove the extern from extern void funcfoo(); you are forward declaring it so you're code below will know what funcfoo() is. If you were to do that to a variable, you would actually be instantiating it and would conflict with your other file. Hence the extern is saying "it exists, trust me ;)" that it gets resolved from your other file.
Another way to think about it is that when you do int varfoo memory is allocated to hold the variable so it is both a definition and a declaration, when you do int foo() the function is declared but not defined so in a way the memory is not allocated. For functions the linkage is external by default so removing it doesn't matter but for the variable, if you say extern int varfoo the compiler will not allocate memory for it --it will assume that the variable is defined somewhere else.
I know this might be late, but I hope this helps in some way. Check the link below and it ll give an idea of what extern is and how it works.
http://www.geeksforgeeks.org/understanding-extern-keyword-in-c/
Thank you