Calling C++ from C in a freestanding way - c++

I have a kernel attempt written in C++, and I was wondering about porting it to x86_64 UEFI, but the EFI bootloader, that uses the GNU-efi lib, must be written in C.
How can I jump to the main kernel function from C? Using extern C all the way makes the use of the C++ characteristics impossible, maybe some assembly code could be used, or I could make the bootloader call an ELF file that would be the main kernel with an ELF loader. Are this solutions viable?

Using extern C all the way makes the use of the C++ characteristics impossible
It doesn't. There are no problems to write extern "C" in the header and compile your functions with a C++ compiler and use all kinds of C++ features in a separate translation unit.
You just need to avoid the C++ name mangling for the C++ implementation of your entry function. That's what extern "C" does, if you use it for the function declaration.
Here's a small example:
kernel.h
extern "C" void main_entry_point();
kernel.cpp
#include "kernel.h"
void main_entry_point() {
// use std::string, std::vector, etc.
}
bootloader.c
#include "kernel.h"
// call main_entry_point()
main_entry_point();

Related

Calling a global function defined in C++ source file , from a C source file

Is there any way to call a C++ function from a C source file , without using extern "C" prior to the function declaration in the C++ file e.g :
//C++ source file
extern "C" void func_name();
void func_name()
{
....
}
The only way to not use extern "C" directly is to manually determine the mangled name and call that from C; which is essentially just doing extern "C" but manually. There's no point or purpose or alternative method with any merit whatsoever.
I'm not aware of any combination of C and C++ compilers that provide an officially supported way to do this. You're supposed to use extern "C" in the C++-side header files.
However, perhaps you have to anyway; I can think of several reasons other than homework, such as when you've got a third-party C++ library with an interface that could be invoked from C but the developers neglected to put extern "C" in the headers, and you can't recompile it.
There is usually an unofficial way to do it: you have to find out the mangled name of the C++ function, and any hidden parameters that it has (this is almost always treated as a hidden first parameter, and there may be others). You then write a declaration on the C side using the mangled name and the full parameter list.
Here is a very simple example that will work with GCC on most operating systems and CPUs:
/* file1.cpp */
#include <cstdio>
void foo()
{
puts("hello from foo");
}
/* file2.c */
#include <stdio.h>
extern void _Z3foov(void);
int main(void)
{
puts("hello from main");
_Z3foov();
return 0;
}
Because this is homework I am not going to give you a more complicated example, but I am going to point you at the so-called "Itanium C++ ABI", which specifies how the mangling and the hidden parameters work with GCC and Clang on most operating systems and CPUs. (Be aware that MSVC uses a completely different, undocumented, scheme. I have heard rumors that Clang can optionally use MSVC's scheme now but I'm not sure I believe it, considering how gargantuan a reverse-engineering job it would have been. ;-)
(In case you're wondering, mangled names are how function and operator overloading are implemented in the linker. If my file1.cpp had defined both void foo(void) and void foo(int), that would have produced an object file exporting the mangled names _Z3foov and _Z3fooi.)
You could write a separate translation unit, let's say mycppunit.cpp containing your void func_name() implementation without any extern "C" declarations. Compile this translation unit into a binary using a C++ compiler, yielding, for example, a mycppunit.o binary; then, use a command line tool like nm to find out how the function name has been mangled: For example:
nm mycppunit.o | grep func_name
would give something like
000000010006a920 T __Z9func_namev
Then you may assume that there will be a function void _Z9func_namev() available, and you can write in a translation unit, e.g. `my_c_program.c, the following:
void _Z9func_namev();
int main() {
_Z9func_namev();
}
Compiling this with a C compiler and linking it together with the mycppunit.o will give the desired result.
Hope it is what you are looking for.

Is it possible for a C method not be able to be included in a C++ project?

I know I can include C methods inside a C++ project using the extern "C" thing. But lets us now suppose that I'm thinking in creating a C++ project that would use quite a lot of C methods coming from both libraries made by me as well as libraries made by other people/companies whose developing details and compilation specifications I'm simply not aware of.
Is it possible that some of this methods of C libraries, with unknown compilation and configuration details, could not be included in my C++ project with extern "C"? Or are all C methods necessarily 100% compatible with C++ code insofar extern "C" is used?
It's possible that some of the functions exported by C use names that collide with C++ keywords. You wouldn't be able to declare those using extern "C".
Functions exported by assembler could even use names that conflict with C keywords.
Those and functions declared static can still be called via function pointer, as long as the library gives you a way to get one.
Headers might not be parse-able in C++ mode for the same reasons -- things like the restrict keyword.
Other than naming issues, C++ has full support for the C calling convention. That's what extern "C" is all about.
C has constructs for interfaces that are not compatible with C++, in particular variable length arrays. In modern C you would write
void matMult(size_t n, size_t k, size_t m, double A[n][k], double B[k][m], double C[n][m]);
this interface can not be included as such in C++ compilation units.
Although rather unlikely, one possible issue that might arise with extern "C" in-place is when a function pointer declared extern "C" points to a C++ function that is not declared extern "C". See the last part of this page for more details.

Two dynamic libraries, one in C other in C++, using eachother

Hoi,
I have a dynamic library loader, which is written in C++ but provides a C-compatible API.
That loader can load modules, which are written in any programming language. They're arranged in a named list and can request function pointers of other modules. Now, a module written in C and compiled with a C compiler gets the functions pointers of any other module, which is written and compiled in C++.
So my question: Are function-pointers cross-compiler valid? I think I heard of something like __cdecl once, long time ago. I use Linux 64bit.
T.I.A.
// my C++ code ...
extern "C" {
void thisFunctionWillBeCallableFromC();
}
void butThisOneMayNot();
struct S
{
void thisDefinitelyWontBeCallableFromC(std::map<int, S>);
};
C++ code should declare interfaces with extern "C" linkage to be callable from C.
Or do you mean C++ code generated by different compilers?
Function pointers are compatible between C and C++.
The only limitation, is that you have to declare your C-functions with extern "C" linkage when used within C++:
extern "C"
{
int foo();
}

When to use extern "C"?

I know how to use extern "C" but what are the conditions when you have to use it?
extern "C" tells the C++ compiler not to perform any name-mangling on
the code within the braces. This allows you to call C functions from
within C++.
For example:
#include <string.h>
int main()
{
char s[] = "Hello";
char d[6];
strcpy_s(d, s);
}
While this compiles fine on VC++. But sometimes this is written as:
extern "C" {
#include <string.h>
}
I don't see the point. Can you give a real example where extern "C" is necessary?
You use extern "C" to prevent name mangling inside header files and your C++ object files for libraries or objects that have already been compiled without mangling.
For example, say you have a widget library which was compiled with a C compiler so that its published interface is non-mangled.
If you include the header file as is into your code, it will assume the names are mangled and those mangled versions are what you'll tell the linker to look for.
However, since you'll be asking for something like function#intarray_float_charptr and the widget library will have only published function, you're going to run into problems.
However, if you include it with:
extern "C" {
#include "widget.h"
}
your compiler will know that it should try to use function, the non-mangled version.
That's why, in header files for C stuff meant to be included in C _or C++ programs, you'll see things like:
#ifdef __cplusplus
extern "C" {
#endif
// Everything here works for both C and C++ compilers.
#ifdef __cplusplus
}
#endif
If you use a C compiler to include this, the #ifdef lines will cause the extern "C" stuff to disappear. For a C++ compiler (where __cplusplus is defined), everything will be non-mangled.
One very common use of extern "C" when you are exporting a function from a library. If you don't disable C++ name mangling you can otherwise make it very hard for clients of your library to name your function. And likewise, when going in the other direction, when you are importing a function that has been exported with C linkage.
Here is a concrete example of where things break and need extern "C" to get fixed.
module.h:
int f(int arg);
module.c:
int f(int arg) {
return arg + 1;
}
main.cpp:
#include "module.h"
int main() {
f(42);
}
Since I am mixing C and C++, this won't link (of the two object files, only one will know f under its C++ mangled name).
Perhaps the cleanest way to fix this is by making the header file compatible with both C and C++:
module.h:
#ifdef __cplusplus
extern "C" {
#endif
int f(int arg);
#ifdef __cplusplus
}
#endif
When you link with libraries that are written in C extern tells the compiler not to decorate the names so that the linker can find the functions. In C++ function names et al have information for the linker e.g. argument types and sizes contained in the name.
If you are producing a binary library A that exposes a function that you would like to call from binary B.
Imagine A is A.dll and B is B.exe and you are on a Windows system.
C++ does not describe a binary layout such that B knows how to call A. Typically this problem is worked around by using the same compiler to produce A and B. If you want a more generic solution you use the extern keyword. This exposes the function in a C manner. C does describe a binary format so that different binaries from different compilers can talk to each other.
See:
http://en.wikipedia.org/wiki/Application_binary_interface
http://en.wikipedia.org/wiki/Name_mangling#Name_mangling_in_C.2B.2B
If, inside your C++ code, you #include a header for an external library (coded in C) and if the functions there are not declared extern "C" they wont work (you'll get undefined reference at link time).
But these days, people coding C libraries and providing header files for you tend to know that, and often put the extern "C" in their header file (suitably protected with #ifdef __cplusplus)
Perhaps a better way to understand is to use (assuming you have a Linux system) the nm utility to show you the (unmangled) names used in a library or an executable.

When to use extern "C" in simple words? [duplicate]

This question already has answers here:
What is the effect of extern "C" in C++?
(17 answers)
Closed 8 years ago.
Maybe I'm not understanding the differences between C and C++, but when and why do we need to use
extern "C" {
? Apparently its a "linkage convention".
I read about it briefly and noticed that all the .h header files included with MSVS surround their code with it. What type of code exactly is "C code" and NOT "C++ code"? I thought C++ included all C code?
I'm guessing that this is not the case and that C++ is different and that standard features/functions exist in one or the other but not both (ie: printf is C and cout is C++), but that C++ is backwards compatible though the extern "C" declaration. Is this correct?
My next question depends on the answer to the first, but I'll ask it here anyway: Since MSVS header files that are written in C are surrounded by extern "C" { ... }, when would you ever need to use this yourself in your own code? If your code is C code and you are trying to compile it in a C++ compiler, shouldn't it work without problem because all the standard h files you include will already have the extern "C" thing in them with the C++ compiler?
Do you have to use this when compiling in C++ but linking to already built C libraries or something?
You need to use extern "C" in C++ when declaring a function that was implemented/compiled in C. The use of extern "C" tells the compiler/linker to use the C naming and calling conventions, instead of the C++ name mangling and C++ calling conventions that would be used otherwise. For functions provided by other libraries, you will almost never need to use extern "C", as well-written libraries will already have this in there for the public APIs that it exports to both C and C++. If, however, you write a library that you want to make available both in C and in C++, then you will have to conditionally put that in your headers.
As for whether all C code is C++ code... no, that is not correct. It is a popular myth that C++ is a "superset of C". While C++ certainly strives to be as compatible with C as possible, there are some incompatibilities. For example, bool is valid C++ but not valid C, while _Bool exists in C99, but is not available in C++.
As to whether you will ever need to use extern "C" with the system's ".h" files.... any well-designed implementation will have those in there for you, so that you do not need to use them. However, to be certain that they are provided, you should include the equivalent header file that begins with "c" and omits ".h". For example, if you include <ctype.h>, almost any reasonable system will have the extern "C" added; however, to be assured a C++-compatible header, you should instead include the header <cctype>.
You may also be interested in Mixing C and C++ from the C++ FAQ Lite.
The other answers are correct, but a complete "boilerplate" example will probably help. The canonical method for including C code in C and/or C++ projects is as follows:
//
// C_library.h
//
#ifdef __cplusplus
extern "C" {
#endif
//
// ... prototypes for C_library go here ...
//
#ifdef __cplusplus
}
#endif
-
//
// C_library.c
//
#include "C_library.h"
//
// ... implementations for C_library go here ...
//
-
//
// C++_code.cpp
//
#include "C_library.h"
#include "C++_code.h"
//
// ... C++_code implementation here may call C functions in C_library.c ...
//
Note: the above also applies to calling C code from Objective-C++.
C++ compilers mangle the names in their symbol table differently than C compilers. You need to use the extern "C" declaration to tell the C++ compiler to use the C mangling convention instead when building the symbol table.
I use 'extern c' so that C# can read my C++ code without having to figure out the extra name mangling done when exporting a C++ dll function. Otherwise, there are extra nonsensical (or really, non-English) characters that I have to add at the end of a function entry point on the C# side in order to properly access a C++ function in a dll.
extern "C" {} blocks tell a C++ compiler to use the C naming and calling conventions. If you don't use this you will get linker errors if trying to include a C library with your C++ project because C++ will mangle the names. I tend to use this on all my C headers just in case they are ever used in a C++ project:
#ifdef __cplusplus
extern "C" {
#endif
/* My library header */
#ifdef __cplusplus
} // extern
#endif
You need to use extern "C" when you want to use the C calling convention in code compiled by a C++ compiler. There are two reasons for this:
You have a function implemented in C and want to call it from C++.
You have a function implemented in C++ and want to call it from C. Note that in this case you can only use the C part of C++ in the function interface (no classes, ...).
Apart from C this also applies when you want to interoperate between C++ and other languages which use the same calling and naming conventions as C.
Typically the declarations in a C header file are surrounded with
#ifdef __cplusplus
extern "C" {
#endif
[... C declarations ...]
#ifdef __cplusplus
}
#endif
to make it usable from C++.
C++ functions are subject to name mangling. This makes them impossible to call directly from C code unless extern "C" is used.