C/C++ struct question - c++

Suppose you have a .cpp file (that is, compiled using a C++ compiler like MSVC). In that file, you define a struct in the following way:
struct Pixel
{
float x, y;
};
In the same file, you have a line of code that will call a C function, that requires a C struct equal to Pixel. If you write:
Pixel my_pixel
// set my_pixel to something
c_func(&my_pixel);
will it work? I mean, the C++ compiler will create the object my_pixel, but it will pass it to a function that is compiled as C code (i have only a .lib of that library).

If the header file is correct, it will work, assuming the C compiler and the C++ compiler use compatible calling conventions. Make sure the header file has an appropriate extern "C" block that contains the function definition.

The reason David Schzwartz says you need an extern "C" block is that without the extern "C" block, the compiler will "mangle" the name of the C function you are calling at the point you call it. If you are calling a C function and not a C++ function, the function's definition in your library will not have a mangled name, so your executable will fail to link.
That's what you want if the function you are calling is written in C++, as name mangling allows for function name overloading. The types of each of a function's parameters are compactly encoded in the mangled function name.
Name mangling was originally provided in C++ to allow C++ object files to be linked with legacy linkers, rather than having to provide a C++-specialized linker that has explicit support for overloaded functions.
C doesn't permit function name overloading, so C function names are never mangled. To provide a prototype in C++ for a single C function you do this:
extern "C" Foo( int theInt );
If you have a whole header file full of C function prototypes and you want to #include that header from a C++ source, enclose the #include in an extern C block
extern "C" {
#include "Foo.h"
}

Related

Is there any difference, whether a struct declared in the 'extern "C"' block or not?

Let's say, I have the header file:
#ifdef __cplusplus
extern "C" {
#endif
struct S
{
int i;
double d;
// etc
};
// Or start the 'extern "C"' block here?..
void f(A* a);
#ifdef __cplusplus
}
#endif
It should be used by C/C++ sources.
My question is: if I carry the struct A declaration out of the extern "C", whether this code will be compatible with a library which was built with the struct A declared as extern "C"?
That is, we built a library with the header as it is presented above, then we moved the extern "C" to the position marked by the corresponding comment line and, finally, we are trying to build a C++ application using the resulting header.
If all of this will be successful? In other words, if the extern "C" influence on a struct declaration?
Whether it depends what language (C/C++) the library is written on?
extern by itself declares external linkage, which is a default state for C++ functions.
Specification "C" gives C language linkage.
Only function names and variable names with external linkage have a language linkage, classes and class members are not affected. struct declaration is a class. If that file meant to be used with C code, there might be problem that older C standard do not support declaration in that format.
Specification "C" makes name conventions of externally linked entities compatible with said language, even while compatibility is implementation-dependent. E.g. for gcc your function would have C++ mangled name _Z3fooP1A, but with C it might be just _foo.

How can I implement in C a function declared in a C++ namespace?

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.

Call C++ nonmember function from C

I want to pass the pointer of an instance of a template function to a C function as callback. And It's obviously impossible to declare the template in extern "C".
Is it guaranteed that C++ uses the same calling convention with C for nonmember function? And is there any other effect of declaring a function in extern "C" besides it prevents incompatible name mangling?
Its a bad idea to export C++ methods or template functions directly for a C library. If I have a C++ program then I usually put the C bindings into its separate .cpp + .h file pair and I surround the header file with and extern "C" block and I use only C compatible function declarations there. In the accompanying .cpp file you implement the functions and since its a .cpp file you can access C++ features (templates, classes, ...) in the actual implementation of the binding functions even if their signature is C compatible using C-friendly types.
In your case this case you should put a C binding function into this binder .cpp+.h file and from the implementation of that function you would be able to call an instance of the specified template function easily.
Simple stupid example:
CBindings.h:
// This is the header used by both C++ and C
#ifdef __cplusplus
extern "C" {
#endif
// C compatible function declarations with C-friendly types.
int int_from_string(const char* s);
#ifdef __cplusplus
}
#endif
CBindings.cpp:
#include "CBindings.h"
#include "WhateverCPPHeader.h"
int int_from_string(const char* s)
{
// Since the implementation is in a .cpp file here we can do C++ish things.
return FromString<int>(s);
}
WhateverCPPHeader.h:
// Somewhere in your C++ header files:
template <typename T>
T FromString(const std::string& s);
...
// Template specializations of FromString for several T types
...
Whatever.c:
#include "CBindings.h"
#include <stdio.h>
void my_c_func(void)
{
int i = int_from_string("5");
printf("%d\n", i);
}
This works on all platforms without problems and the cut between C/C++ is clearly separated into its own file.
No. It's not guaranteed that it uses the same calling convention. You can use the calling convention modifiers like _stdcall, cdecl, pascal, etc. So you have to make sure that both sides know the same calling convention.
One way would be detecting the mangled name and define a proper prototype for the C function.
Consider changing the design; since you can't benefit from the template in C anyway, you can define a simple C++ function (defined extern "C") that calls the templated function.

Extern functions in C vs C++

In *.h header files of a C library, should one declare functions
extern void f();
// or only
void f();
when using only in C
when using from C++.
There's [almost] never any need to use the keyword extern when declaring a function, either in C or in C++. In C and in C++ all functions have external linkage by default. The strange habit of declaring functions in header files with extern probably has some historical roots, but it has been completely irrelevant for decades already.
There's one [obscure?] exception from the above in C, which is probably not directly related to what you are asking about: in C language (C99) if in some translation unit a function is defined as inline and also declared as extern (an explicit extern is used) then the inline definition of that function also serves as an external definition. If no declarations with explicit extern are present in the translation unit, then the inline definition is used as "internal" definition only.
P.S. There's such thing as extern "C" in C++, but that is a completely different matter.
In header files of a C library, should one declare functions:
extern void f();
// or only
void f();
Issue 1: Semantics
In a C++ program, the functions are declared as functions returning no value and taking no arguments.
In a C program, the functions are declared as functions returning no value and taking an indeterminate but not variable-length list of arguments.
To get the 'no arguments' meaning in C, use one of:
extern void f(void);
void f(void);
The same notation also means the same thing in C++, though for pure C++ code, using void in the argument list is not idiomatic (do not do it in pure C++ code).
Issue 2: Inter-working between C and C++
Tricky, but the normal rule would that you should declare the functions to C++ code as extern "C". To use the same source code for both, you then need to test the __cplusplus macro. You'd normally do something like:
#ifdef __cplusplus
#define EXTERN_C extern "C"
#define EXTERN_C_BEGIN extern "C" {
#define EXTERN_C_END }
#else
#define EXTERN_C /* Nothing */
#define EXTERN_C_BEGIN /* Nothing */
#define EXTERN_C_END /* Nothing */
#endif
EXTERN_C void f(void);
EXTERN_C_BEGIN
void f(void);
int g(int);
EXTERN_C_END
The options and variations are manifold, but the header can be used by both C and C++.
The macros would normally be defined in one general-purpose header that's used everywhere, and then the particular header would ensure that the general purpose header is included and then use the appropriate form of the macro.
Issue 3: Style
Formally, there is no need for the extern notation before a function declaration. However, I use it in headers to emphasize that it is a declaration of an externally defined function, and for symmetry with those (rare) occasions when there is a global variable declared in the header.
People can, and do, disagree over this; I go with the local rules — but when I'm the rule-maker, the extern is included in a header.
For general use declare as
#ifdef __cplusplus
extern "C" {
#endif
void f(void);
#ifdef __cplusplus
}
#endif
Otherwise, extern is obsolete.
The latter is perfectly fine, since it's only a function definition, which tells those, who include this header: 'There's a function with this prototype somewhere around here'
In this context, functions differ clearly from variables, but that's a different matter.
Make sure though, that you do not include the function body, unless you declare it 'inline' or as part of a class definition (C++) or as a 'template function' (also C++).
Specifying extern in function prototype has no effect, since it is assumed by default. Whenever a compiler sees a prototype, it assumes a function is defined somewhere else (in the current or another translation unit). This holds for both of the languages.
The following thread has some useful comments in general about extern.
Effects of the extern keyword on C functions

Functions with C linkage able to return class type?

I observed a function in a dll which has C linkage. This function returns class type. I am not sure how this is made possible as C doesn't understand class.
I wrote a sample dll and program myself and noted that the VC++ compiler shows a warning to this effect but doesn't stop you. The program is able to GetProcAddress of this function and call it to receive the returned object. The class definition was made available to program.
Furthermore, if I write a function with C linkage that returns a class type where this class is not even exported, the compiler doesn't issue any warning. The program can consume this function from the dll provided the class definition is made available to it.
Any thoughts on how this works? Is such a behavior compiler/platform specific?
You are misunderstanding the behavior of extern "C".
It only impacts the name of the function in the object file by preventing name mangling. It does not make a function neither "more C" or "less C++". The only additional limitation which extern "C" adds to a C++ function is that is shall not be overloaded.
It's possible for functions with C linkage to return objects that can't be expressed in C so long as they can be manipulated in C. According to my copy of Design & Evolution of C++ (section 11.3.3):
We considered several alternatives to the type-safe linkage schemes before deciding on the one actually added to the language [Stroustrup,1988]: ...
provide type-safe linkage only for functions that couldn't be C functions because they had types that couldn't be expressed in C. ...
A function declared to have C linkage still has C++ calling semantics. That is, the formal arguments must be declared, and the actual arguments must match under the C++ matching and ambiguity control rules. ... Had we provided special services for C, we would have been obliged to add an unbounded set of language calling conventions to C++ compilers [for linking to Pascal, Fortran, PL/I, etc.]. ...
Linkage, inter-language calls, and inter-language object passing are inherently difficult problems and have many implementation-dependent aspects. ... I expect we haven't heard the last of this matter.
That is, C++ linkage isn't based on whether the types involved are valid C types. That is an intentional design decision. It allows you to create a DLL compiled in C++ but that can be used from C via a header:
// in the header
struct Foo; // forward declaration
#ifdef __cplusplus
extern "C" {
#endif
struct Foo* create_foo();
void destroy_foo(struct Foo*);
void foo_bar(struct Foo*);
#ifdef __cplusplus
} // extern "C"
// now declare Foo
struct Foo {
void bar();
};
#endif
// in the implementation file
#include <iostream>
extern "C" {
Foo* create_foo()
{
return new Foo();
}
void destroy_foo(Foo* f)
{
delete f;
}
void foo_bar(Foo* f)
{
f->bar();
}
}
void Foo::bar()
{
std::cout << "Foo::bar() called\n";
}
Note the calls to new, delete and std::cout. These all require the C++ runtime. Therefore, the implementation file must be compiled with C++, but since the functions have C linkage, the header can be used from either C or C++.
So how do you get a Foo in C? In this case, you don't, because there's no way to fully declare it in the header in a way that C will understand. Instead, C only sees the forward declaration, which creates an incomplete type. C doesn't know how large an incomplete type is, so C functions can't create it or operate on them directly, but C does know how large a pointer to an incomplete type is, so C can operate on a pointer to an incomplete type. You can get much more creative and actually create POD types in C++ that you can operate on directly in C.
As long as you only use Foo*s in C, you don't have to actually define the Foo struct in C. It so happens that APR uses a similar design ("Creating an APR Type," I couldn't find a better link).
A class object is basically just a struct object, with some extra "hidden" members for the vtbl and so on.
However, I'm not sure what you mean by "the program can consume this function provided the class definition is made available to it". C would throw a compiler error on seeing class Blah { ... };.