Define (not declare) c functions inside extern "C" scope - c++

I saw a section of codes defined inside a .cpp file like this:
extern "C"
{
#include <user_interface.h>
#include <lwip/netif.h>
uint8 wifi_get_opmode(void)
{
return STATION_MODE;
}
bool wifi_station_get_config(struct station_config *config)
{
strcpy((char*)config->ssid, "emulated-ssid");
strcpy((char*)config->password, "emulated-ssid-password");
config->bssid_set = 0;
for (int i = 0; i < 6; i++)
config->bssid[i] = i;
return true;
}
}
My understanding of extern "C" keyword is to disable name mangling, so the functions defined inside a .c file and compiled with a c compiler can be linked and called from a cpp code. Which means, these C functions should be defined inside a .c file, then they will be compiled to a C-type object file by using a C compiler.
However, here the functions enclosed by extern "C" are defined (not declared) inside a .cpp file. What is the purpose of doing this?

The purpose would be to define the functions using "C" linkage. Meaning: don't mangle their names but compile them just like normal C++ functions would be, otherwise.
They can be called directly from C code that gets linked with this translation unit (subject to a suitable declaration), or from another C++ translation unit that declares these symbols as extern "C".

You're actually doing this all the time. When you put extern "C" in header files, the headers are also included in the implementation file for the functions they declare.
To correctly link a function, the function name must be identical in both the translation unit that defines them and the translation unit that includes them, so you have to use extern "C" in both (in the case they are both C++ of course).

Related

how does extern "C" allow C++ code in a C file?

In order to use C++ code in a C file, I read that we can just do extern "C" { (where the c++ code goes here)}, but when I try printing something out using cout, I keep getting an error because it does not recognize the library . I think I am just confused on how extern "C" allows you to use C++ code in C.
The opposite is true. You can use extern C to add code you want to compile as C code using a C++ compiler.
Unless I'm missing something you can't compile C++ code with a C compiler.
The extern "C" construct is a C++-specific syntax, no C compiler will understand it.
That's why you will almost always see it paired with some conditional compilation like
#ifdef __cplusplus
extern "C" {
#endif
...
#ifdef __cplusplus
}
#endif
What extern "C" does is simply to inhibit name mangling meaning that symbols defined in a C++ source file can be used in a C program.
This allows you to have a project with mixed C and C++ sources, and the C source can call the C++ functions that have been defined as extern "C".
Very simple, and stupid, example just to show the point:
Lets say we have a C source file, compiled with a C compiler:
#include <stdio.h>
void foo(void); // Declare function prototype, so it can be called
int main(void)
{
printf("Calling foo...\n");
foo();
printf("Done\n");
return 0;
}
Then we have a C++ source file for the foo function:
#include <iostream>
extern "C" void foo()
{
std::cout << "Hello from foo\n";
}
The C source file is compiled with a C compiler, and the C++ source file is compiled with a C++ compiler. Then the two object files are linked together to form the executable program. Because foo was defined as extern "C" it's symbol name in the object file is not mangled, and the linker can resolve the reference from the object file created by the C compiler.
It works in the other direction as well. Because symbols in C are not mangled the C++ compiler needs to know that, and that is done by declaring the C symbols extern "C", usually in a header file using the conditional compilation as shown above. If extern "C" was not used, the C++ compiler would think that the symbols were C++ symbols, and mangle the names leading to linker problems when the linker can't find the mangled symbols.
Equally stupid example: First a C++ source file
#include <iostream>
extern "C" void bar(); // Declare function prototype as an unmangled symbol
int main()
{
std::cout << "Calling bar...\n";
bar();
}
Then the C source file
#include <stdio.h>
void bar(void)
{
printf("Inside bar\n");
}
extern "C" is a way of putting C code in C++ code. More specifically it tells the compiler to disable certain things like function overloading so that it can also turn off the name mangling. In C++ a simple function like:
int add(int a, int b) {
return a+b;
}
Will actually get some funky name in the library to denote the parameters so that if you define another function like:
double add(double a, double b) {
return a+b;
}
That it knows which one to call. You don't want that if you're trying to use a C library and that's what extern "C" is for. All of this being said, extern "C" does not allow C++ in a C program.
Exported C++ symbols, as generated my the compiler, are mangled to include additional type information about the symbol to the linker.
So the following overloaded functions would be distinguishable by the linker in C++, but not C:
int fn();
int fn(int);
int fn(char*);
int fn(char*) const;
int fn(const char*);
The extern "C" { ... } syntax allows symbols (or references to C symbols) to be defined in C++ code without using the mangling rules.
This allows such C++ code to be linked with C libraries.

Calling C functions within C++

I have a medium length C file with a bunch of functions (NOT under a header file - just a bunch of functions), that I wish to gather and use under a C++ project I'm developing.
Now I've read about the extern function but I've only seen it work on small C functions that are under a .h file.
But I wish to include these functions without messing with the C files themselves since I don't really understand them - I just need the function "under the hood". Is there any easy simple solution to this problem?
Yes, you just need some extern "C" declarations visible in your C++ code:
extern "C" {
int my_C_function_1(void);
int my_C_function_2(void);
}
This can either go in a suitable header, or if it's only used within one particular .cpp file then you could just put it there.
Note that if your C functions are already declared within a C header somewhere you can just do this within your .cpp file:
extern "C" {
#include "my_C_header.h"
}
You need to make a C++ header file myheader.hh. It starts with
#ifndef MYHEADER_INCLUDED
#define MYHEADER_INCLUDED
extern "C" {
then you declare all your public C functions, types, macros, etc.... At last you end it with
}; // end extern C
#endif MYHEADER_INCLUDED
In your C++ program, add #include "myheader.hh"
Alternatively (and instead of using myheader.hh), you might add (after other includes, but before C++ code) in your C++ file something like
extern "C") {
#include "your-C-code.c"
};
(But it might not work).
You'll need to declare the functions, typically in a header file, in order to call them from C++. If you compile these functions with a C compiler, then you will indeed need to surround the declarations with extern "C"; e.g.
extern "C" {
int foo(int, int);
}
If you have the source, then you could also modify it to include the header file (sans extern "C") and compile the functions with your C++ compiler.

__cplusplus macro to tell g++ about C header declarations not working strangely

I have a mix of C C++ code. All compiled with g++. Wherever I have C headers I have the contents of the header file included inside
#if defined(__cplusplus)
extern "C" {
#endif
and
#if defined(__cplusplus)
extern "C" {
#endif
But in one C header file I get g++ compilation errors where I have accidentally used a parameter name as template , which obviously is incorrect and in conflict with c++ keyword template.
I know I can go and change this parameter name, but I am thinking why is this extern "C" declaration not working and why is the header file considered as C++ code and not C as I intended to.
g++ version 4.1.1 Linux Red Hat Enterprise.
The extern "C" only tells the compiler (actually, the linker) that C++ name mangling doesn't apply to the functions declared in that scope. It has nothing to do with the syntax or keywords themselves.
Your best solution is to rename the conflicting symbols.
Consider:
extern "C" {
namespace n
{
int& foo(bool b)
{
if (!b)
throw std::invalid_argument("fail!");
static int i = 0;
return ++i;
}
}
}
This function has C language linkage, but uses references, namespaces and exceptions, which I hope demonstrates that extern "C" doesn't magically switch the compiler to compiling C, it just tells the compiler to use C calling conventions and symbol-naming conventions for the functions and variables with C language linkage (which usually just means it disables name-mangling and causes matching declarations in different namespaces to refer to the same entity.)

C linkage and c++ headers

I want to use some c++ classes in shared library with C linkage. And i got following problems.
If
#include <iostream>
extern "C"
{
void f(){}
}
Compiles and links succesfully, but f() could not be found in resulting library.
If
extern "C"
{
#include <iostream>
void f(){}
}
I got many compiler errors (just dont know how to correctly translate them in english, something about template with C linkage) on every occurence of C++ keyword "template" in iostream and included headers.
What should be done?
The first variant is correct. Only stuff that even exists in C can be declared in a extern "C" block, and templates and classes certainly don't belong in that category. You only have to make sure, that your function is also declared as extern "C" in the header if you are using a C++-compiler. This is often achieved by writing
#ifdef __cplusplus
// C++ declarations (for example classes or functions that have C++ objects
// as parameters)
extern "C"
{
#endif
// C declarations (for example your function f)
#ifdef __cplusplus
}
#endif
in the header.
The first is correct; system headers (and most other headers as well)
can only be included at global scope, outside any namespaces, classes,
functions or linkage specification blocks. There are likely things in
<iostream> that wouldn't be legal in an extern "C", and even if
there weren't, the name mangling for extern "C" is almost certainly
different from that of C++, and the library itself was surely compiled
as extern "C++".
How did you define f? This could be a similar problem: if the source
file compiles it as an extern "C++" function, then the name will be
mangled differently than it was in the client files which compiled it as
an extern "C" function.
The general policy here is to handle the headers and the function
definitions/declarations in the same way you normally do, except that
you ensure that the header can be included in both C and C++ sources,
e.g.:
#if __cplusplus
extern "C" {
#endif
void f();
// Other `extern "C"` functions...
#if __cplusplus
}
#endif
Then include this header in all files where the function f() is used,
and in the file where it is defined.
Use __declspec to export functions, classes, etc...
Also: http://msdn.microsoft.com/en-us/library/a90k134d(v=vs.80).aspx
And this one is very good: http://www.flounder.com/ultimateheaderfile.htm

How does an extern "C" declaration work?

I'm taking a programming languages course and we're talking about the extern "C" declaration.
How does this declaration work at a deeper level other than "it interfaces C and C++"? How does this affect the bindings that take place in the program as well?
extern "C" is used to ensure that the symbols following are not mangled (decorated).
Example:
Let's say we have the following code in a file called test.cpp:
extern "C" {
int foo() {
return 1;
}
}
int bar() {
return 1;
}
If you run gcc -c test.cpp -o test.o
Take a look at the symbols names:
00000010 T _Z3barv
00000000 T foo
foo() keeps its name.
Let's look at a typical function that can compile in both C and C++:
int Add (int a, int b)
{
return a+b;
}
Now in C the function is called "_Add" internally. Whereas the C++ function is called something completely different internally using a system called name-mangling. Its basically a way to name a function so that the same function with different parameters has a different internal name.
So if Add() is defined in add.c, and you have the prototype in add.h you will get a problem if you try to include add.h in a C++ file. Because the C++ code is looking for a function with a name different to the one in add.c you will get a linker error. To get around that problem you must include add.c by this method:
extern "C"
{
#include "add.h"
}
Now the C++ code will link with _Add instead of the C++ name mangled version.
That's one of the uses of the expression. Bottom line, if you need to compile code that is strictly C in a C++ program (via an include statement or some other means) you need to wrap it with a extern "C" { ... } declaration.
When you flag a block of code with extern "C", you're telling the system to use C style linkage.
This, mainly, affects the way the linker mangles the names. Instead of using C++ style name mangling (which is more complex to support operator overloads), you get the standard C-style naming out of the linker.
It should be noted that extern "C" also modifies the types of functions. It does not only modify things on lower levels:
extern "C" typedef void (*function_ptr_t)();
void foo();
int main() { function_ptr_t fptr = &foo; } // error!
The type of &foo does not equal the type that the typedef designates (although the code is accepted by some, but not all compilers).
extern C affects name mangling by the C++ compiler. Its a way of getting the C++ compiler to not mangle names, or rather to mangle them in the same way that a C compiler would. This is the way it interfaces C and C++.
As an example:
extern "C" void foo(int i);
will allow the function to be implemented in a C module, but allow it to be called from a C++ module.
The trouble comes when trying to get a C module to call a C++ function (obviously C can't use C++ classes) defined in a C++ module. The C compiler doesn't like extern "C".
So you need to use this:
#ifdef __cplusplus
extern "C" {
#endif
void foo(int i);
#ifdef __cplusplus
}
#endif
Now when this appears in a header file, both the C and C++ compilers will be happy with the declaration and it could now be defined in either a C or C++ module, and can be called by both C and C++ code.
In C++ the name/symbol of the functions are actually renamed to something else such that different classes/namespaces can have functions of same signatures. In C, the functions are all globally defined and no such customized renaming process is needed.
To make C++ and C talk with each other, "extern C" instructs the compiler not to use the C convention.
extern "C" denotes that the enclosed code uses C-style linking and name mangling. C++ uses a more complex name mangling format. Here's an example:
http://en.wikipedia.org/wiki/Name_mangling
int example(int alpha, char beta);
in C: _example
in C++: __Z7exampleic
Update: As GManNickG notes in the comments, the pattern of name mangling is compiler dependent.
extern "C", is a keyword to declare a function with C bindings, because C compiler and C++ compiler will translate source into different form in object file:
For example, a code snippet is as follows:
int _cdecl func1(void) {return 0}
int _stdcall func2(int) {return 0}
int _fastcall func3(void) {return 1}
32-bit C compilers will translate the code in the form as follows:
_func1
_func2#4
#func3#4
in the cdecl, func1 will translate as '_name'
in the stdcall, func2 will translate as '_name#X'
in the fastcall, func2 will translate as '#name#X'
'X' means the how many bytes of the parameters in parameter list.
64-bit convention on Windows has no leading underscore
In C++, classes, templates, namespaces and operator overloading are introduced, since it is not allowed two functions with the same name, C++ compiler provide the type information in the symbol name,
for example, a code snippet is as follows:
int func(void) {return 1;}
int func(int) {return 0;}
int func_call(void) {int m=func(), n=func(0);}
C++ compiler will translate the code as follows:
int func_v(void) {return 1;}
int func_i(int) {return 0;}
int func_call(void) {int m=_func_v(), n=_func_i(0);}
'_v' and '_i' are type information of 'void' and 'int'
Here is a quote from msdn
"The extern keyword declares a variable or function and specifies that it has external linkage (its name is visible from files other than the one in which it's defined). When modifying a variable, extern specifies that the variable has static duration (it is allocated when the program begins and deallocated when the program ends). The variable or function may be defined in another source file, or later in the same file. Declarations of variables and functions at file scope are external by default."
http://msdn.microsoft.com/en-us/library/0603949d%28VS.80%29.aspx