How to declare an extern C function inside a function in C++? - c++

I have an inline function, roughly like this:
inline void SomeFunction() {
extern void SomeOtherFunction();
SomeOtherFunction();
}
This is a simplification: my functions do have parameters and return values.
However, I want this header to work in both C and C++ files. Currently, linking fails because C++ files attempt to find an implementation of SomeOtherFunction with C++ linkage. I thought I could just fix this by using extern "C":
inline void SomeFunction() {
#ifdef __cplusplus
extern "C" void SomeOtherFunction();
#else
extern void SomeOtherFunction();
#endif
SomeOtherFunction();
}
This causes Clang to fail with:
error: expected unqualified-id
extern "C" void SomeOtherFunction();
^
How can I do this correctly?

extern "C" is a linkage-specification. C++ standard section 7.5 Linkage specifications paragraph 4 states that:
A linkage-specification shall occur only in namespace scope (3.3).
E.g. you can say extern "C" in global namespace or some specific namespace. Outside of namespaces it is illegal.
Function declarations are possible though in smaller scopes. If you remove linkage specification your code will compile (but not link):
inline void SomeFunction() {
extern void SomeOtherFunction();
SomeOtherFunction();
}
If you really need SomeOtherFunction declaration in a smaller scope (e.g. hide from global scope) you can put your declaration into a header file to a dedicated scope and then use in your function:
Header:
namespace other {
extern "C" void SomeOtherFunction();
}//namespace other
Code:
void SomeFunction()
{
other::SomeOtherFunction();
}
Credit goes to these two answers on stackoverflow: here and here.

From the C++11 standard (in [dcl.link], emphasis mine):
4 Linkage specifications nest. When linkage specifications nest, the innermost one determines the language linkage. A linkage specification does not establish a scope. A linkage-specification shall occur only in namespace scope.
(linkage-specification refers to extern string-literal ..., i.e. extern "C" in your case.)
This means you can't have extern "C" inside of a class or function.
What's the point of declaring SomeOtherFunction inside of SomeFunction? It still has to be a global symbol and visible to the linker.
So why not do this?
#ifdef __cplusplus
extern "C"
#endif
void SomeOtherFunction();
inline void SomeFunction() {
SomeOtherFunction();
}
The following also seems to work:
extern "C" {
inline void SomeFunction() {
extern void SomeOtherFunction();
SomeOtherFunction();
}
}
But it would have the side effect of making SomeFunction also use C linkage (which is hopefully OK as (per your requirements) it needs to be usable from C, too).

You can do this like that. I assume you have a header file, a C source and a C++ source.
Header file:
inline void SomeFunction()
{
void SomeOtherFunction_Bridge();
SomeOtherFunction_Bridge();
}
C++ source:
extern "C"
{
void SomeOtherFunction();
}
void SomeOtherFunction_Bridge()
{
SomeOtherFunction();
}
C source:
void SomeOtherFunction()
{
// Function with a code doing something
}
void SomeOtherFunction_Bridge()
{
SomeOtherFunction();
}
Checked on GCC, it compiles.

extern tells the compiler that a symbol (function, variable) is defined in some other module. When this module (C++ file) is compiled, object file contains a list of external symbols it needs. So this is on a level of a C++ file, it cannot be in smaller scope (function, block).

Related

Program for a 4x4 keypad calculator using assemply files as the operation functions. Mbed Using a nucleo f401re microcontroller [duplicate]

I have an inline function, roughly like this:
inline void SomeFunction() {
extern void SomeOtherFunction();
SomeOtherFunction();
}
This is a simplification: my functions do have parameters and return values.
However, I want this header to work in both C and C++ files. Currently, linking fails because C++ files attempt to find an implementation of SomeOtherFunction with C++ linkage. I thought I could just fix this by using extern "C":
inline void SomeFunction() {
#ifdef __cplusplus
extern "C" void SomeOtherFunction();
#else
extern void SomeOtherFunction();
#endif
SomeOtherFunction();
}
This causes Clang to fail with:
error: expected unqualified-id
extern "C" void SomeOtherFunction();
^
How can I do this correctly?
extern "C" is a linkage-specification. C++ standard section 7.5 Linkage specifications paragraph 4 states that:
A linkage-specification shall occur only in namespace scope (3.3).
E.g. you can say extern "C" in global namespace or some specific namespace. Outside of namespaces it is illegal.
Function declarations are possible though in smaller scopes. If you remove linkage specification your code will compile (but not link):
inline void SomeFunction() {
extern void SomeOtherFunction();
SomeOtherFunction();
}
If you really need SomeOtherFunction declaration in a smaller scope (e.g. hide from global scope) you can put your declaration into a header file to a dedicated scope and then use in your function:
Header:
namespace other {
extern "C" void SomeOtherFunction();
}//namespace other
Code:
void SomeFunction()
{
other::SomeOtherFunction();
}
Credit goes to these two answers on stackoverflow: here and here.
From the C++11 standard (in [dcl.link], emphasis mine):
4 Linkage specifications nest. When linkage specifications nest, the innermost one determines the language linkage. A linkage specification does not establish a scope. A linkage-specification shall occur only in namespace scope.
(linkage-specification refers to extern string-literal ..., i.e. extern "C" in your case.)
This means you can't have extern "C" inside of a class or function.
What's the point of declaring SomeOtherFunction inside of SomeFunction? It still has to be a global symbol and visible to the linker.
So why not do this?
#ifdef __cplusplus
extern "C"
#endif
void SomeOtherFunction();
inline void SomeFunction() {
SomeOtherFunction();
}
The following also seems to work:
extern "C" {
inline void SomeFunction() {
extern void SomeOtherFunction();
SomeOtherFunction();
}
}
But it would have the side effect of making SomeFunction also use C linkage (which is hopefully OK as (per your requirements) it needs to be usable from C, too).
You can do this like that. I assume you have a header file, a C source and a C++ source.
Header file:
inline void SomeFunction()
{
void SomeOtherFunction_Bridge();
SomeOtherFunction_Bridge();
}
C++ source:
extern "C"
{
void SomeOtherFunction();
}
void SomeOtherFunction_Bridge()
{
SomeOtherFunction();
}
C source:
void SomeOtherFunction()
{
// Function with a code doing something
}
void SomeOtherFunction_Bridge()
{
SomeOtherFunction();
}
Checked on GCC, it compiles.
extern tells the compiler that a symbol (function, variable) is defined in some other module. When this module (C++ file) is compiled, object file contains a list of external symbols it needs. So this is on a level of a C++ file, it cannot be in smaller scope (function, block).

C inline function used from C++ code

I am trying to call an inline function defined in C from C++ code and I am getting an unresolved symbol error. Can I even do this?
In def.h:
#ifdef __cplusplus
extern "C" {
#endif
#include "types.h"
extern inline void foo();
#ifdef __cplusplus
}
#endif /* extern "C" */
In def.c:
inline void foo()
{
some code
}
Elsewhere in c++ code:
void bar()
{
foo();
}
And this is where I get an unresolved symbol error. Is there a way to make this compile? And if so, how will it work? Will the compiler replace the function call in my C++ code by the C definition? Eliminating functional calls is important as this is for an embedded environment.
Thank you.
Most compilers generate code on source file level; to generate code, the compiler must "see" the source of all functions for which it needs to generate code. Unless you have LTO/LTGC, you have to make the source of all inline functions available in every file where they are called.
Try moving the source of the inlined function(s) into the corresponding header:
def.h:
#ifdef __cplusplus
extern "C" {
#endif
#include "types.h"
inline void foo()
{
some code
}
#ifdef __cplusplus
}
#endif /* extern "C" */
def.c:
Remove foo() definition from this file (or remove this file).
Elsewhere in c++ code:
#include "def.h"
void bar()
{
foo();
}
The definition of the inlined C function should go into a header visible and included by your C++ code.

External linkage and »extern "C"« block

I have an int ID, which I want to define in C++ and make available for C linkage (contrived case for the sake of simplicity):
/* i.h */
#ifdef __cplusplus
extern "C" {
#endif
extern int ID;
#ifdef __cplusplus
}
#endif
Here's a C and a C++ program using the int:
/* m.cpp */
#include "i.h"
#include <iostream>
int main() { std::cout << ID << std::endl; }
/* m.c */
#include "i.h"
#include <stdio.h>
int main() { printf("%d\n", ID); }
Now what I'm wondering is the syntax of extern "C" and/or extern. Here's how int ID can and cannot be defined:
/* i.cpp */
// const int ID = 88; // no C linkage, obviously, LNK2019/1120
// extern "C" const int ID = 88; // provides C linkage
// extern "C" { const int ID = 88; } // no C linkage, surprisingly, LNK2019/1120
// extern "C" { extern const int ID = 88; } // C linkage restored
Compiling:
cl /nologo /W4 m.cpp i.cpp /MD /EHsc
cl /nologo /W4 m.c i.cpp /MD
What I don't understand is the syntax when extern "C" is used with a {block}. I have to repeat the extern, whereas with the blockless form of extern "C" I do not. Is this just a syntax quirk or is there more to it?
I stumbled upon this issue on page 98 of Inside COM by Dale Rogerson. There is a code listing with the nested extern and a comment intended to clarify (but which I don't understand):
#include <objbase.h>
extern "C"{
extern const IID IID_IX = {0x32bb8320, 0x41b, 0x11cf, ...};
// The extern is required to allocate memory for C++ constants.
}
Can anyone explain the internal extern?
The inner extern means what expected: "the symbol is defined somewhere else, it has external linkage, don't allocate space for it in this unit (unless defined here as well)".
The outer extern "C" { ... } has maybe a bit misleading syntax, it only tells the compiler "if you are creating names of any symbols with external linkage inside this block, use traditional C naming (C language linkage) instead of C++ name mangling (C++ language linkage) for them". But it does not specify that all things inside the block are "defined somewhere else" (have external linkage) -- they are still declared with the default internal linkage. That's why you need the inner extern as well.
The one-line variant extern "C" <variable declaration> is just a shorthand, as you probably want to define an external variable if you care about its cross-unit symbol name.
(As a side-note, I would include i.h also in i.cpp, that way I wouldn't have to remember to mess with extern "C" any more in the implementation.)
The problem is that const and extern are warring with each other. const means (among other things), "Make this definition internal, unless there's an explicit extern on it.". When the definition is in an extern "C" block, there's no extern directly on the definition, so the "implicit internal" from the const takes precedence. The other definitions all have an extern directly on the definition, so it becomes external.
Here's how int ID can and cannot be defined:
Careful! extern "C" has different effects in different contexts.
N3797 §7.5/7:
A declaration directly contained in a linkage-specification is treated
as if it contains the extern specifier (7.1.1) for the purpose of
determining the linkage of the declared name and whether it is a
definition. Such a declaration shall not specify a storage class.
extern "C" int i; // declaration
extern "C" {
int i; // definition
}
So the second line in your snippet is just a declaration whilst your third line is also a definition. This changes what effect the linkage-specification has on the declarations - you can't give a name defined in a C++ translation unit C linkage. You have to make it a pure declaration.

Export duplicated functions in two namespaces (C++)

I have these two namespaces, each one containing a function with the same name, like
namespace group1 {
void add(int arg) {
}
}
namespace group2 {
void add(bool arg) {
}
}
and I specify this in the header with the declarations
#ifdef __cplusplus
extern "C" {
#endif
// My namespaces and functions prototypes here
#ifdef __cplusplus
}
#endif
and I am trying to export them into a DLL, with GCC. I get a warning about a conflict between them because they have the same name, then an error at linking time. I thought the name was mangled in the object file based on the arguments, too. I don't know if the linker cares about the namespace too. How could I make this work? Thanks.
If these are C++ functions, you have to remove the extern "C" bracketing:
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus 
    }
#endif
extern "C" tells the compiler "don't mangle this name"--but (as you say) you want the mangling.
You can't really do that directly. When you use the extern "C", you are declaring that the functions are exported as if they were C functions, not C++.
This means (among other things)
Namespaces are removed, and are not considered part of the name
No name mangling due to arguments is done
The best you can do is create extern "C" functions which redirect.
#ifdef __cplusplus
extern "C" {
#endif
void group1_add(int arg);
void group2_add(bool arg);
#ifdef __cplusplus
}
#endif
And the implementations of the wrapper functions would then use either group1::add() or group2::add() as appropriate.

C++ Extern / Multiple Definitions

I am trying to interface to Ada in C++ using externs. What is the difference between these two implementations?
Implementation A
namespace Ada
{
extern "C"
{
int getNumber();
int index;
int value;
}
}
Implementation B
namespace Ada
{
extern "C"
{
int getNumber();
}
extern "C" int index;
extern "C" int value;
}
Both implementations compile just fine. But Impl-A fails to link, I get a multiple definition error for index and value. I'm just trying to understand the differences.
extern "C" only conveys the linking conventions to use for the code within the extern "C" block. Anything in that block will be linked against as if it were pure c. Confusingly, extern int is totally different. It means that you promise there is an actual int named index and an actual int named value somewhere, but they cannot be found here. In your implementation-A the ints are actually not extern in the second sense - the extern "C" only implies that they provide a strict c linking convention.
Same keyword but totally different uses, which is unfortunate since it leads to weird issues like this. Mixing them is legal (obviously), but they don't behave together the way that their name implies.
EDIT
See Charle's response for the true definition of the extern weirdness as defined in the C++ standard.
A linkage-specifier (i.e. extern "C" or extern "C++") applied to a brace enclosed sequence of declarations has no effect on whether the enclosed declarations are definitions or not, however a linkage-specifier applied to a single declaration is treated as an extern specifier for the purposes of determining whether a declaration is also a definition. (7.5 para 7 of C++03)
So:
extern "C" { int a; } // a is declared and defined
extern "C" int a; // a is just a declaration (as if extern int a;)
extern "C" int a = 0; // a is a definition because of the initializer.
I'm not sure why the second works, but you want
namespace Ada
{
extern "C"
{
int getNumber();
extern int index;
extern int value;
}
}
because you only want to declare index and value, not define them. (See this answer for the difference.)