Xcode c/c++ undefined symbols - c++

I have a .cpp file which I declare a function
#ifndef MyFile_hpp
#define MyFile_hpp
#ifdef __cplusplus
extern "C" {
#endif
void runCode();
#ifdef __cplusplus
}
#endif
#endif
This works fine. I can call this function within my Objc. In my implementation I have an extern void that it will not let me call. It's giving the undefined symbols. I need this to build as is, the extern will be declared in a different file upon compiling. Having the extern, should this compiler just trust me and let me build?
#include "MyFile.h"
extern int runMe();
#ifdef __cplusplus
extern "C" {
#endif
void runCode() {
runMe();
}
#ifdef __cplusplus
}
#endif

I think what you are doing is probably correct.
The compiler doesn't just trust you. A C++ function is declared to the linker using additional characters, or "decorations" that define the full detail of the cclass it is a member of and all its arguments. A C function has none of that, just the raw name, so it is easy for the linker to tell the difference.

Related

extern "C" - before or after library header includes?

I'm writing a C library, which may potentially be useful to people writing C++. It has a header which looks like this:
#ifndef FOO_H_
#define FOO_H_
#include <bar.h>
#include <stdarg.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
void foo_func();
#ifdef __cplusplus
}
#endif
#endif
and I was wondering - should I move the extern "C" bit before including the header include directives? Especially seeing how, in practice, some of those headers might themselves have an extern "C"?
NO, in general you shouldn't move it to include the headers.
extern "C" is used to indicate that the functions is using the C calling convention. The declaration has no effect on variables and #defines, so there is no need to include these. If an #include is inside an extern "C" block, this effectively modifies the function declarations inside that header file!
Background: Without the extern "C" declaration, when compiling using a C compiler, a function is assumed to follow the C convention, and when compiling using a C++ compiler, the C++ convention is assumed. In case the same header file is used for C and C++ code, you would get a linker error, since the compiled function has different names in C and C++.
Although it's possible to put all your code between the #ifdef blocks, I personally don't like it, because it's really only intended for the function prototypes, and I frequently see people copy-pasting this at places where it shouldn't be. The cleanest way is to keep it where it's supposed to be, which is around the function prototypes in a C/C++ header file.
So, to answer your question "should I move the extern "C" bit before including the header include directives?", my answer is: No, you shouldn't.
But is it possible? Yes, and in many cases this won't break anything. Sometimes it is even necessary, if the function prototypes in an external header file are incorrect (e.g. when they are C functions and you want to call them from C++) and you cannot change that library.
However, there are also cases where doing so breaks the build. Here's a simple example that fails to compile if you wrap the include using extern "C":
foo.h:
#pragma once
// UNCOMMENTING THIS BREAKS THE BUILD!
//#ifdef __cplusplus
//extern "C" {
//#endif
#include "bar.h"
bar_status_t foo(void);
//#ifdef __cplusplus
//}
//#endif
foo.c:
#include <stdio.h>
#include "foo.h"
#include "bar.h"
bar_status_t foo(void)
{
printf("In foo. Calling bar wrapper.\n");
return bar_wrapper();
}
bar.h:
#pragma once
typedef enum {
BAR_OK,
BAR_GENERIC_ERROR,
BAR_OUT_OF_BEAR,
// ...
} bar_status_t;
extern "C" bar_status_t bar_wrapper(void);
bar_status_t bar(void);
bar.cpp:
#include <iostream>
#include "bar.h"
extern "C" bar_status_t bar_wrapper(void)
{
std::cout << "In C/C++ wrapper." << std::endl;
return bar();
}
bar_status_t bar(void)
{
std::cout << "In bar. One bear please." << std::endl;
return BAR_OK;
}
main.cpp:
#include <stdio.h>
#include <stdlib.h>
#include "foo.h"
#include "bar.h"
int main(void)
{
bar_status_t status1 = foo();
bar_status_t status2 = bar();
return (status1 != BAR_OK) || ((status2 != BAR_OK));
}
When uncommenting the blocks in a.h, I get the following error:
main2.cpp:(.text+0x18): undefined reference to `bar'
collect2.exe: error: ld returned 1 exit status
Makefile:7: recipe for target 'app2' failed
Without, it builds fine. A C main calling only C functions from foo and bar will build fine either way, since it's unaffected by the #ifdef __cplusplus blocks.
Surprisingly yes. After reading the standard now even I would write
#ifndef FOO_H_
#define FOO_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <bar.h>
#include <stdarg.h>
#include <stddef.h>
void foo_func();
#ifdef __cplusplus
}
#endif
#endif
For 2 reasonss:
1 Having nested extern "C" are no problem, so your bar.h include would be fine. Like this it looks clearer and more important
2 To be really portable your surprisingly have to wrap an extern "C" around your C headers for C++ users, if they don't want to.
Because I just looked thru the C++ Standard and 16.5.2.3 Linkage [using.linkage] states
Whether a name from the C standard library declared with external linkage has extern
"C" or extern "C++" linkage is implementation-defined. It is
recommended that an implementation use extern "C++" linkage for this
purpose.1
To be safe than sorry, you indeed should wrap an extern "C" around those includes but, you should not have to, since this implies to the headers in D.9 C headers [depr.c.headers] like <stdlib.h> which you are using.
This is covered in the C++ FAQ.
First, How to include a standard C header file in C++ code? Nothing special is needed, as standard C header files work seamlessly with C++. So you don't need to wrap stdarg.h and stddef.h in extern "C".
Then, for non-standard C headers, there are two possibilities: either you can’t change the header, or you can change the header.
When you can't change the C header, wrap the #include in extern "C".
// This is C++ code
extern "C" {
// Get declaration for f(int i, char c, float x)
#include "my-C-code.h"
}
int main()
{
f(7, 'x', 3.14); // Note: nothing unusual in the call
// ...
}
When you can change the header, edit it to conditionally include extern "C" in the header itself:
#ifdef __cplusplus
extern "C" {
#endif
. . .
#ifdef __cplusplus
}
#endif
In your case it comes down to whether you have control over the contents of bar.h. If it's your header, then you should modify it to include extern "C" and not wrap the #include itself.
Headers should work the same way regardless of how/when/where they are included. Wrapping an #include in extern "C", #pragma pack, special #defines, etc, should be reserved for last resort workarounds, as this may interfere with how the header behaves in different scenarios, reducing the system's maintainability in the long run.
As StoryTeller said in the comments:
Some headers are explicitly written under the assumption that the outermost "scope" has C++ language linkage. They may use __cplusplus to remove template declarations, and if you wrap them up like you wish to, your header will be fundamentally broken. So as mentioned already, make your declarations correct, and let other headers do their thing unimpeded. Even standard library headers may break (since an implementer may reason its going to be shared anyway, and then do some expert friendly things inside).
Note that standard C headers may be implemented using C linkage, but may also be implemented using C++ linkage. In which case wrapping them in extern "C" might result in link errors.

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.

Does it make sense to use _attribute__ ((nothrow)) inside extern C?

I have some C code being called from C++.
The header resembles the following:
#ifndef CLibH
#define CLibH
#ifdef __cplusplus
extern "C" {
#endif
//C API
void foo(void);
// ...
#ifdef __cplusplus
}
#endif
#endif
Since I'm already using extern C,
is there any benefit to adding the nothrow compiler attribute?
#ifndef CLibH
#define CLibH
#ifdef __cplusplus
extern "C" {
#endif
//C API
void foo(void) __attribute__((nothrow));
// ...
#ifdef __cplusplus
}
#endif
#endif
Does extern C make this redundant?
Are there still advantages to applying it under these circumstances?
Yes, it does. From gcc documentation:
For example, most functions in the standard C library can be
guaranteed not to throw an exception with the notable exceptions of
qsort and bsearch that take function pointer arguments.

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.

Does extern "C" have any effect in C?

I just got some C code that uses extern "C" to declare external functions like this:
extern "C" void func();
Is this valid C? I'm getting an error at this line, but I'm not sure if it's because of this or something else.
No, it's not valid C. It should only be used in C++ code to refer to functions defined in C code. The extern "C" should be surrounded in a ifdef __cplusplus/#endif block:
// For one function
#ifdef __cplusplus
extern "C"
#endif
void func();
// For more than one function
#ifdef __cplusplus
extern "C"
{
#endif
void func1();
void func2();
#ifdef __cplusplus
}
#endif
this is a C++ notation to tell the compiler/linker to use C calling standards.
Usually that line is wrapped in an pre-processor statement.
#ifdef __cplusplus
extern "C" {
#endif
// stuff
#ifdef __cplusplus
}
#endif
Not valid in C. If present after preprocessing this will result in a diagnostic as per the standard.
For C++, this turns of name-mangling. See this for more details as to why it may be required. Can you post some more details?