0

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

  • 1
    Is there a file called hi.c in the root directory? – user253751 Nov 20 '15 at 03:43
  • Perhaps you meant `char* path = (char*)"./hi.c";` instead (added a dot in `./`) – Code Different Nov 20 '15 at 04:36
  • I'll look into this some more, but it looks like the problem here is that somehow the file cannot be opened. myFun() is definitely called if "FAIL" is printed. This looks to be a quick example you wrote as a demo, and the problem in your actual project is probably different. The functions in the real C++ lib have C++ linkage, and you will have trouble calling them from Swift. You need to write a C++ wrapper. I have an article on that here: http://www.swiftprogrammer.info/swift_call_cpp.html – Anatoli P Nov 20 '15 at 04:39
  • BTW, the implementation of myFun() and its prototype have different return types. I'm sure that's a typo. – Anatoli P Nov 20 '15 at 04:42

1 Answers1

1

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!

Community
  • 1
  • 1
Anatoli P
  • 4,791
  • 1
  • 18
  • 22
  • Thank you for your answer! I didn't log in stack overflow and found your answer at that time, so we found other ways to deal with our problem. Anyway, thanks for your answer, and I may hope it will help others. – Gongbaochicken Jan 04 '16 at 17:33