Read file fail when call C++ function in Swift code - c++

guys.
I am writing an iOS app in swift, and I need to call some C++ lib. So I've build a simple example on how to bridge between C++ and Swift, and test on an iTouch. I wrapped the C++ interface with extern C. But I can't read the file when I call C++ function. Here is the code.
When I click the button on the iOS device, it needs to call the myFun():
main.swift
#IBAction func button(sender: AnyObject) {
myFun()
}
myFun() is my C++ function, which just reads a local file("hi.c").
DlibFun.cpp
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include "DlibFun.h"
#include <unistd.h>
void myFun(){
char* path = (char*)"/hi.c";
FILE* f = fopen(path, "r");
if(f != NULL){
printf("open it\n");
fclose (f);
}else{
printf("FAIL\n");
}
}
Wrapper the C++ code in C
DlibFun.h
#ifdef __cplusplus
extern "C" {
#endif
int myFun();
#ifdef __cplusplus
}
#endif
photo-Bridging-Header.h
#include "DlibFun.h"
The result is that every time it prints out "FAIL". And any one give me any hint? I have tried the different path, but none of them are correct. Is it possible that my path is wrong? or there is any thicky thing that I don't know?
File folder

As you said, the code in the question is a simple example. I don't think the problem you are asking about, namely the fact that "FAIL" is output, is related to the real difficulties of bridging between C++ and Swift. The C++ function is called correctly, but the file can't be opened, most likely because it isn't there or isn't readable. In fact, I reproduced your example in Xcode, and got the output "open it" as long as the file was available; otherwise it would be "FAIL," as in your case.
Because DlibFun.cpp includes DlibFun.h, where myFun() is declared extern "C", the C++ compiler will compile myFun() to have C linkage, meaning it can be called from C and Swift. When Swift sees myFun() through the bridging header, it just treats it as a C function and calls it as such.
In a real-world situation, myFun() would be implemented in some C++ library and compiled using a C++ compiler, giving it C++ linkage, so just creating a header in Xcode, declaring myFun() extern "C", and then including the header in the bridge won't help. The build will fail with a link error.
To call the C++ library function myFun() you can write a wrapper as follows:
///////////////////
// File DlibFunW.h:
#ifndef DlibFunW_h
#define DlibFunW_h
// Because this is a C file for use by Swift code, via
// the bridge header, we don't need #ifdef __cplusplus.
// And because myFunW() was marked extern "C" in our C++
// wrapper, it's just a C function callable from Swift.
void myFunW();
#endif /* DlibFunW_h */
////////////////////
// File DlibFun.cpp:
#include "DlibFun.h"
// This file is C++ because it calls myFun(), which is
// a function with C++ linkage.
// This code is visible only to the C++ compiler, so
// we don't need #ifdef __cplusplus
extern "C" void myFunW() { myFun(); }
Now we don't need extern "C" in DlibFun.h, since myFun() has C++ linkage, as a real-world C++ library function would. The bridging header is now just
#include "DlibFunW.h"
and Swift calls myFunW() instead of myFun().
Of course, this is a very simple example dealing only with the C vs. C++ linkage problem. A real-world C++ function would take parameters and return values, often of pointer, struct, and class types, and dealing with those is a completely different can of worms. Here on StackOverflow you'll find plenty of info on that. Some questions I'd recommend:
Swift converts C's uint64_t different than it uses its own UInt64 type
How do I get a specific bit from an Integer in Swift?
Converting inout values to UnsafeMutablePointer<Unmanaged<TYPE>?>
Is it possible to convert a Swift class into C void* pointer?
Can I mix Swift with C++? Like the Objective - C .mm files
Hope you find useful info there, all the best!

Related

Swift Bridging header from C++ is not Working

My need was that I want to call a swift function from my cpp code. I have tried Using Bridging method for this purpose. When I try to call a swift from c it is working. Since C and C++ are similar, I used the same logic in C++ ,but it is not working.
Compilation of this CPP code gives error like
Undefined symbol: sayHello()
.
My c and c++ sample code is like this ,
CToSwift-Bridging-Header.h
void callCpp();
extern void sayHello();
main.c/.cpp
#include <stdio.h>
#include "CToSwift-Bridging-Header.h"
int main(int argc, const char * argv[]) {
printf("Hello, Main!\n");
callCpp();
return 0;
}
void callCpp() {
printf("CPP: Hi This is C\n");
printf("CPP: Swift say hello to everyone !\n");
sayHello();
printf("CPP: Nice! ");
}
Testswift.swift
import Foundation
#_cdecl("sayHello")
func sayHello()
{
print ("Swift:Hello , Welcome to Swift")
}
After reading some available documentation for this concept, I understand Swift (Obj c) and C++ is not directly related since both are evolved from C on different manner.
But my queries are
1] Is something else which I am missing in this Bridging header method to call a swift function from a C++ Code?
2] Is there any other Method to achieve my goal ?
3] Can we able to pass the swift code as a library or dll when compiling C++ ?
This looks like a name mangling issue.
C++ adds information to the name of each function that encodes the parameter and return types so that overloading with different parameter types works.
The normal trick to include C headers (which your bridging header is effectively) is an extern "C" { ... } If I remember correctly from my C++ programming days 20 years ago, it should go like this:
#ifdef __cplusplus
void callCpp();
extern "C" {
#endif
extern void sayHello();
#ifdef __cplusplus
}
#endif
Everything inside the extern "C" { ... } will be treated by the C++ compiler as straight C and so no name mangling will be done. The compiler will remember this if it encounters the function implementation inside C++ code and will apply no name mangling to it either so the extern declaration and the implementation have matching names.
The ifdefs stop C (and Swift) from seeing the C++ extern "C" { ... }.
On the assumption that you want callCpp() to use C++ conventions, I've put it outside the extern "C" but inside the ifdef so it is not visible to C and Swift programs.

How do I call C++ functions from C?

I'm writing a C program (myapp) which needs to use a particular api; the api is written in C++. I've worked with C and C++, but never both at once, and I'm getting confused.
So, the api provides the following directory, which I've placed in a folder called include, at the same level as my makefile:
libmyapi.a
api/api.h
My main source file is src/myapp.c, and it includes the api using #include "api/api.h".
My make command is (plus some flags, which I haven't listed because I don't think they're relevant here):
gcc -Linclude -lmyapi -Iinclude src/myapp.c -o lib/myapp.sp -lrt
The problem I'm having is that the api.h file contains references to namespaces etc. Eg at one point it has:
namespace MyAPI {
namespace API {
typedef SimpleProxyServer SimpleConnection;
}
}
and obviously the C compiler doesn't know what this means.
So, I assumed I'd need to compile using a C++ compiler, but then someone said I didn't, and I could just "wrap" the code in "extern 'C'", but I don't really understand. Having read around online, I'm not any further on.
Do I need to compile in C++ (ie using g++)?
Do I need to "wrap" the code, and what does that mean? Do I just do
#ifdef __cplusplus
extern "C" {
namespace MyAPI {
namespace API {
typedef SimpleProxyServer SimpleConnection;
}
}
}
#endif
or do I just wrap the lines
namespace MyAPI {
namespace API {
and then their corresponding }}?
The header file calls other header files, so potentially I'll need to do this in quite a lot of places.
So far I've got errors and warnings with all the variations I've tried, but I don't know whether I'm doing the wrapping wrong, setting g++ compiler flags wrong, using the wrong compiler, or what! If I know the method to use, I can at least start debugging. Thank you!
You can write a small C++ program that creates a C binding for the API.
Gvien this API:
namespace MyAPI {
namespace API {
typedef SimpleProxyServer SimpleConnection;
}
}
you can create c_api.h
#ifdef __cplusplus
extern "C" {
#endif
struct api_handle_t;
typedef struct api_handle_t* api_handle;
api_handle myapi_api_create();
void myapi_api_some_function_using_api(api_handle h);
void myapi_api_destroy(api_handle h);
#ifdef __cplusplus
}
#endif
and c_api.cpp
#include "c_api.h"
#include <myapi/api/stuff.hpp>
struct api_handle_t
{
MyAPI::API::SimpleConnection c;
};
api_handle myapi_api_create()
{
return new api_handle_t;
}
void myapi_api_some_function_using_api(api_handle h)
{
//implement using h
}
void myapi_api_destroy(api_handle h)
{
delete h;
}
compile that with a C++ compiler and include the c_api.h file in the C project and link to the library you created with the C++ compiler and the original library.
Basically, your C++ library needs to export a pure C API. That is, it must provide an interface that relies solely on typedef, struct, enum, preprocessor directives/macros (and maybe a few things I forgot to mention, it must all be valid C code, though). Without such an interface, you cannot link C code with a C++ library.
The header of this pure C API needs to be compilable both with a C and a C++ compiler, however, when you compile it as C++, you must tell the C++ compiler that it is a C interface. That is why you need to wrap the entire API within
extern "C" {
//C API
}
when compiling as C++. However, that is not C code at all, so you must hide the extern "C" from the C compiler. This is done by adding the preprocessor directives
#ifdef __cplusplus1
extern "C" {
#endif
//C API
#ifdef __cplusplus1
}
#endif
If you cannot change your libraries header, you need to create a wrapper API that offers this pure C API and calls through to the respective C++ code.
How do I call C++ functions from C?
By writing calling functions whose declarations are valid in the common subset of C and C++. And by declaring the functions with C language linkage in C++.
The problem I'm having is that the api.h file contains references to namespaces
Such header is not written in common subset of C and C++, and therefore it cannot be used from C. You need to write a header which is valid C in order to use it in C.
Do I need to compile in C++ (ie using g++)?
If you have function definitions written in C++, then you need to compile those C++ functions with a C++ compiler. If you have C functions calling those C++ functions, then you need to compile those C functions with C compiler.
A minimal example:
// C++
#include <iostream>
extern "C" void function_in_cpp() {
std::cout << "Greetings from C++\n";
}
// C
void function_in_cpp(void);
void function_in_c(void) {
function_in_cpp();
}
You cannot. You can use C functions in your C++ program. But you cannot use C++ stuff from C. When C++ was invented, it allowed for compatibility and reuse of C functions, so it was written as a superset of C, allowing C++ to call all the C library functions.
But the reverse is not true. When C was invented, there was no C++ language defined.
The only way you can call C++ functions is to convert your whole project into a C++ one... you need to compile your C functions with a C++ compiler (or a C compiler if they are plain C) but for a C function to call a C++ function it must be compiled as C++. You should declare it with:
extern "C" {
void my_glue_func(type1 param1, type2 param2, ...)
{
/* ... */
}
} /* extern "C" */
and link the whole thing as a C++ program (calling the c++ linker)
This is because C doesn't know anything about function overloading, class initializacion, instance constructor calls, etc. So if you even can demangle the names of the C++ functions to be able to call them from C (you had better not to try this), they will probably run uninitialized, so your program may (most) probably crash.
If your main() function happens to be a C function, then there's no problem. C++ was designed with this thing in mind, and so, main() is declared implicitly as extern "C". :)

Passing a file as a parameter to a C++ method from Swift

I am trying to call some C++ code in a Swift application. I did not write the C++ nor do I have control over it.
I have created a C++ wrapper to handle the calls from Swift. I also added some test functions within the C++ files to verify that I am calling the C++ from Swift. Those functions simply return an int.
In the C++ header code there is a function defined as follows:
class GlobeProcessor {
public:
void readFile(ifstream &inputFile);
// ...
};
In my wrapper I have defined the function as follows:
extern "C" void processGlobe(ifstream &file) {
GlobeProcessor().readFile(file);
}
The confusing part is how to reference this in my bridging header. Currently the bridging header contains the following:
// test function
int getNumber(int num);
void processGlobeFile(ifstream &file);
The test function succeeds, so I am able to access the C++ from Swift. However, adding a declaration for processGlobeFileto the bridging header produces the following compile error:
Unknown type name 'ifstream'
I have tried unsuccessfully to add the appropriate imports to the bridging header. I am not a seasoned C++ guy, so i don't really know if I'm approaching this in the correct manner. Can somebody help me to understand how to pass a file as a parameter to a C++ method from Swift?
Thanks!
Swift can't import C++. ifstream is a C++ class and the parameter is also a C++ reference. Neither of these are going to work with Swift.
You have to write a C function that wraps your C++ call and treats your ifstream object as an opaque reference.
Also your wrapper function has to be declared extern "C" not just defined that way, otherwise other C++ files that include the header will assume it has name mangling.
Something like this might work but I haven't tested it at all:
// header
#if !defined _cplusplus
typedef struct ifstream ifstream; // incomplete struct def for C opaque type
#else
extern "C" {
#endif
int getNumber(int num);
void processGlobeFile(ifstream *file); // note you need to use a pointer not a reference
#if defined __cplusplus
} // of the exten C
#endif

C++ program using a C library headers is recognizing "this" as a keyword. Extern "C" error?

My C++ program needs to use an external C library.
Therefore, I'm using the
extern "C"
{
#include <library_header.h>
}
syntax for every module I need to use.
It worked fine until now.
A module is using the this name for some variables in one of its header file.
The C library itself is compiling fine because, from what I know, this has never been a keyword in C.
But despite my usage of the extern "C" syntax,
I'm getting errors from my C++ program when I include that header file.
If I rename every this in that C library header file with something like _this,
everything seems to work fine.
The question is:
Shouldn't the extern "C" syntax be enough for backward compatibility,
at least at syntax level, for an header file?
Is this an issue with the compiler?
Shouldn't the extern "C" syntax be enough for backward compatibility, at least at syntax level, for an header file? Is this an issue with the compiler?
No. Extern "C" is for linking - specifically the policy used for generated symbol names ("name mangling") and the calling convention (what assembly will be generated to call an API and stack parameter values) - not compilation.
The problem you have is not limited to the this keyword. In our current code base, we are porting some code to C++ and we have constructs like these:
struct Something {
char *value;
char class[20]; // <-- bad bad code!
};
This works fine in C code, but (like you) we are forced to rename to be able to compile as C++.
Strangely enough, many compilers don't forcibly disallow keyword redefinition through the preprocessor:
#include <iostream>
// temporary redefinition to compile code abusing the "this" keyword
#define cppThis this
#define this thisFunction
int this() {
return 1020;
}
int that() {
return this();
}
// put the C++ definition back so you can use it
#undef this
#define this cppThis
struct DumpThat {
int dump() {
std::cout << that();
}
DumpThat() {
this->dump();
}
};
int main ()
{
DumpThat dt;
}
So if you're up against a wall, that could let you compile a file written to C assumptions that you cannot change.
It will not--however--allow you to get a linker name of "this". There might be linkers that let you do some kind of remapping of names to help avoid collisions. A side-effect of that might be they allow you to say thisFunction -> this, and not have a problem with the right hand side of the mapping being a keyword.
In any case...the better answer if you can change it is...change it!
If extern "C" allowed you to use C++ keywords as symbols, the compiler would have to resolve them somehow outside of the extern "C" sections. For example:
extern "C" {
int * this; //global variable
typedef int class;
}
int MyClass::MyFunction() { return *this; } //what does this mean?
//MyClass could have a cast operator
class MyOtherClass; //forward declaration or a typedef'ed int?
Could you be more explicit about "using the this name for some variables in one of its header files"?
Is it really a variable or is it a parameter in a function prototype?
If it is the latter, you don't have a real problem because C (and C++) prototypes identify parameters by position (and type) and the names are optional. You could have a different version of the prototype, eg:
#ifdef __cplusplus
extern "C" {
void aFunc(int);
}
#else
void aFunc(int this);
#endif
Remember there is nothing magic about header files - they just provide code which is lexically included in at the point of #include - as if you copied and pasted them in.
So you can have your own copy of a library header which does tricks like the above, just becoming a maintenance issue to ensure you track what happens in the original header. If this was likely to become an issue, add a script as a build step which runs a diff against the original and ensures the only point of difference is your workaround code.

Impact of using extern "C" { on C++ code when using g++

When using G++ (e.g. version 4.5 on Linux) can anyone explain what will/can happen if a user writes a header file for a mixed C/C++ system like this:
#ifdef __cplusplus
extern "C" {
int myCPPfunc(some_arg_list....); /* a C++ function */
}
#endif
but here myCPPfunc() is a normal C++ function with a class def inside - i.e. it was wrongly labeled as a C function.
What is the impact of this?
The main impact of this is that you cannot overload it, e.g. this is legal:
int myCPPfunc(int a);
int myCPPfunc(char a);
But this is not:
extern "C"
{
int myCPPfunc(int a);
int myCPPfunc(char a);
}
It is perfectly legitimate to have the implementation of an extern "C" function use arbitrary C++ features. What you can't do is have its interface be something you couldn't do in C, e.g. argument overloading, methods (virtual or otherwise), templates, etc.
Be aware that a lot of the "something you couldn't do in C" cases provoke undefined behavior rather than prompt compile errors.
This tells the C++ compiler that the functions declared in the header file are C functions.
http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html#faq-32.2
This is exactly what extern "C" is for - it allows you to write a C++ function that can be called from C.
Essentially, that declaration is telling the C++ compiler that you want the C++ function myCPPfunc() to have an external interface that is linkable (and therefore callable) from C.
The implementation of the function is still C++ and can still use C++ features.
Typically, the declaration of the function in the header file might look more like:
#ifdef __cplusplus
extern "C" {
#endif
int myCPPfunc(some_arg_list....); /* a C++ function */
#ifdef __cplusplus
}
#endif
That lets the same header file be used by either the C++ compiler or the C compiler, and each will see it as declaring a C callable function.