How to make a callback function pointer from C++ to Swift? - c++

There are many tutorials to make this on web but none are clear and objective, because thats I'm prefer show my case.
I'm developing a iOS app that use a C API to connect to a service web and it have callback functions, my task is simple, I must get events generateds in C code on Swift code. To this I tried some ways, the current way that I'm trying is the follow.
Scenario
I've three files: wrapper.cpp, Bridging-Header.h and ViewController.swift
On Briding-Header.h I declared a function's pointer.
Bridging-Header.h
void callback_t(void(*f)(unsigned char*));
On wrapper.cpp I wrote my code to connect to web and use callback functions. So this is the callback method to get state connection when is disconnected.
wrapper.cpp
void callback_web_disconnected(unsigned char *c) {
printf("Disconnected %s",c);
// Here I want invoke a method to Swift code
callback_t(r); // But this not works
}
It's not compiles, error message: Use of undeclared identifier 'callback_t'.
If I try write: void callback_frame(unsigned char*);, linker command failed with exit code 1 error occurs.
ViewController.swift
func callback_t(_ f: ((UnsafeMutablePointer<UInt8>?) -> Void)!) {
print("ARRIVED ON VIEWCONTROLLER!")
// Here I want get the error code (unsigned char*) passed as parameter
}
I can't import Bridging-Header.h file on wrapper.cpp because cause many conflicts.

First, callback_t is not an identifier. I don't see it typedef anywhere..
Second, you need some way of telling C++ that the callback is your swift function. To do that, I pass it as a parameter to the C++ function similar to how we do it in Objective-C and Swift.. Otherwise you need to store the callback in a global variable somewhere and have C++ access it.
Using the first method of passing the callback as a parameter:
First in the C++ header (Foo.h) I did (Do NOT remove the ifdef stuff.. the compiler uses C linkage when importing to Swift but when compiling the C++ side, it'll be mangled so to make it use C linkage, we extern "C" the code):
#ifndef Foo_hpp
#define Foo_hpp
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef void(*callback_t)(const char *);
void callback_web_disconnected(callback_t);
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* Foo_hpp */
Then in the implementation file (Foo.cpp) I did:
#include "Foo.h"
#include <thread>
#include <iostream>
#ifdef __cplusplus
extern "C" {
#endif
void callback_web_disconnected(callback_t callback)
{
std::thread t = std::thread([callback] {
std::this_thread::sleep_for(std::chrono::seconds(2));
if (callback)
{
callback("Hello World");
}
});
t.detach();
}
#ifdef __cplusplus
} // extern "C"
#endif
Then in ViewController.swift I did:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
callback_web_disconnected({
if let ptr = $0 {
let str = String(cString: ptr)
print(str)
}
})
}
}
It works fine. The Swift code gets called from C++ after 2 seconds has passed.
Using the second method of storing the callback in a global variable (which I despise but let's not get into that)..
In Foo.h I did:
#ifndef Foo_hpp
#define Foo_hpp
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef void(*callback_t)(const char *);
callback_t globalCallback; //Declare a global variable..
void callback_web_disconnected();
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* Foo_hpp */
In Foo.cpp I did:
#include "Foo.h"
#include <thread>
#include <iostream>
#ifdef __cplusplus
extern "C" {
#endif
void callback_web_disconnected()
{
std::thread t = std::thread([] {
std::this_thread::sleep_for(std::chrono::seconds(2));
if (globalCallback)
{
globalCallback("Hello World");
}
});
t.detach();
}
#ifdef __cplusplus
} // extern "C"
#endif
In ViewController.swift, I did:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//Set the globalCallback variable to some block or function we want to be called..
globalCallback = {
if let ptr = $0 {
let str = String(cString: ptr)
print(str)
}
}
//Trigger our test.. I guess your C++ code will be doing this anyway and it'll call the globalCallback.. but for the sake of this example, I've done it here..
callback_web_disconnected()
}
}

Related

Right way to initialize a static library (C++)?

I have a static C library that I want to port to C++, in the C library I got some global variables that store some common data used by the functions for example:
// global variable in the C library
int global_number_of_cpu_cores;
init_global_vars()
{
global_number_of_cpu_cores = get_info();
}
void lib_function()
{
// use global_number_of_cpu_cores
}
when using the library, it must be first initialized by the init function but in C++, the object's constructors are executed before the main function, so I cannot code:
class class_lib
{
class_lib()
{
// use global_number_of_cpu_cores but this is uninitialized!
}
}
Also, you can initialize global variables with functions:
int program_var = lib_function(); // lib_function uses global_number_of_cpu_cores but this is unintialized!
what is a decent/elegant way to solve this when designing a C++ library?
how do well-designed C++ libraries like Boost, Qt, etc solve this? any idea?
What you can do - simply create a C wrapper interface for C++ I.e. something like following:
In header file, e.g. foo.h
#ifndef __FOO_H_INCLUDED__
#define __FOO_H_INCLUDED__
#ifdef __cplusplus
extern "C" {
#endif
void print_logical_cpus()
#ifdef __cplusplus
}
#endif / * extern "C" */
#endif / * __FOO_H_INCLUDED__ */
in the implementation file e.g. foo.cpp
#include "foo.h"
#include <cstdio>
#include <thread>
struct GlobalSettings {
GlobalSettings():
logical_cpus(std::thread::hardware_concurrency())
{}
std::size_t logical_cpus;
};
static GlobalSettings __gsettings;
extern "C" {
void print_logical_cpus()
{
std::printf("Logical cpus %z", __gsettings.logical_cpus);
}
}
If you still need to port on raw C, there are compiler specific tricks to run functions before and after main.
GCC uses attribute((constructor)) and attribute((destructor)))
MS VC++ uses __declspec(allocate(".CRT$XLC"))

Undefined reference when use c-function from c++ file

I just begin new project in eclipse. Try to use C-library from C++ file.
In headers, where are prototypes of functions, here is:
#ifdef __cplusplus
extern "C" {
#endif
// prototypes...
void Init_Configuration(void);
#ifdef __cplusplus
}
#endif
It's initialize.h. In main.cpp i include this file and try use function:
#include "initialize.h"
int main()
{
Init_Configuration();
// Life cycle
while (1)
{
}
}
After compilation i get this error:
initialize.c:54: undefined reference to `SPI_Cmd'
In source C file "initialize.c", where i also include "initialize.h" i use function from C-library for stm32f2xx:
#include "initialize.h"
#include "stm32f2xx_rcc.h"
#include "stm32f2xx_spi.h"
#include "stm32f2xx_gpio.h"
// some code
SPI_Cmd(SPI1, DISABLE);
// some code
In this library also is this code:
#ifdef __cplusplus
extern "C" {
#endif
...
I don't know where a problem. Please, help!

how can make a variable created in .h become global scope to the program [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I am mixing some code made in C++ into code made in C (generated by lex/yacc).
I have a pointer (void pointer to a C++ class) which is visible to the main and inside of parser() (the parsing function generated by yacc). This pointer is located in the .h of the parser as you can see below.
I want the object pointed by con have a global scope, actually, the pointer it have a global scope, I can access to the class in main as in parser function, but the object inside not. I mean, I can work and add data to it in parser but when it come back to main is empty, not destroy but empty. It look like the object inside parse is other as in main.
I want to have only one object in the entire project. How I do that?
Note: I will like to stay only one object, so I don't want to discuss about the copy constructor (that it works and has be tested), I just one object (something like singleton).
================================= main.cpp ========================================
#include <stdio.h>
#include <stdlib.h>
#include "Context.h"
extern "C" {
#include "parser.h"
}
int main(int argc, char** argv) {
*stderr = *stdout;
con = new_Context();
yyin=fopen(argv[1],"rb");
ret = yyparse();
return ret;
}
================================ parser.h ==========================================
#ifndef PARSER
#define PARSER
#include <stdio.h>
#include <stdlib.h>
#include "C_Context.h"
// ================ updated ========================
#define LINKAGE extern
#ifdef __cplusplus
extern "C" {
#endif
LINKAGE C_Context *con;
#ifdef __cplusplus
}
#endif
// ================ updated ========================
extern FILE* yyin;
int yyparse();
#endif
===================================== parser.c ======================================
// ================ updated ========================
#include "parser.h"
#ifdef __cplusplus
extern "C" {
#endif
C_Context *con;
#ifdef __cplusplus
}
#endif
// ================ updated ========================
#include "y.tab.c"
================================== C_Context.h (fragmrnt) =======================
typedef void C_Context;
typedef void C_TypeGroup;
#ifdef __cplusplus
extern "C" {
#endif
// create a context and return the class as void pointer
C_Context * new_Context();
#ifdef __cplusplus
}
#endif
=================================== C_Context.cpp (fragment) ===============
#include "Context.h"
#include <iostream>
#define con (*((Context *)c_con))
using namespace std;
extern "C" {
C_Context * new_Context(){
C_Context* ret =0x0;
try{
ret = (C_Context*) new Context();
}catch(char * ex){
cerr<< "Runtime error:" << ex;
}
return ret;
}
}
UPDATE:
I update with the suggestions you had mad, still not work. Exactly the same problem. I am doing something wrong?
UPDATE 2:
Someone suggest me to describe the problem more. I am not sure what should I describe, but I will try.
I have a class name context that have all the objects an functions that need for implement a interpret. The object is a complex anidations of map/vectors with classes of map/vectors. All go well on parse, I mean, I can access all functionality of context class by it wrapper C_Context. My problem is that the language should first parse an initialization file and then the script, for that the object must context should stay with the data after the first initialization file to be able to correct run the script.
of course there is other way, I can make a temporal file, with all the script and the initialization file. But this limit or difficult the possibility of make some kind of include inside of the language. If I do it so, then I have to first read the file for includes and add all the files on one, to in the end run the real interpret. So I prefer to be able to run the parser many times if is possible. For that I need the context stay the same.
I don't know if this helps but well.
UPDATE 3
I apply that was suggested, as I understand it, still the same thing. Elements are added on the pointer inside parser(), I can play with it. But when I get back to main is empty again (no destroy).
(I check a little bit the grammar and the orthography)
Declare the variable extern in the header and define it in the .c file. Otherwise each translation unit will have its own definition.
UPDATE:
Seeing you have updated your code, parser.c should look like this (just in case the compiler compiles .c files as C++):
// ================ updated ========================
#ifdef __cplusplus
extern "C" {
#endif
C_Context *con;
#ifdef __cplusplus
}
#endif
// ================ updated ========================
#include "y.tab.c"
And you can also remove extern "C" { ... around #include "parser.h" now.
Either in the header like this:
#ifndef myinclude_h
#define myinclude_h
#ifdef MAIN
int x;
#else
extern int x;
#endif
#endif
In this case you must make sure that that somewhere in your compilation process MAIN is defined in exactly one file.
Or the other way as described above:
.h:
#ifndef myinclude_h
#define myinclude_h
extern int x;
#endif
.cpp:
int x;
To elaborate:
If you want to have a global vriable, you delcare it in some header file as above shown with extern. This is just a declartion which tells the compiler that there is "somewhere" a variable of type int with name x.
The in one of your c or cpp files you actually declare the variable in the global space. Means, not inside a class or something, but outside of all functions. For example at the top of main you can write it before main comes:
int x;
main()
{
}
everwhere you want to make use of this variable you must include the headerfile where the extern declaration resides in and then you can access it, just like any other variable.
In the other files:
#include "myinclude.h"
void fkt()
{
if(x < 10)
x+= 10;
cout << x << endl;
}
update
In your main:
#include <stdio.h>
#include <stdlib.h>
#include "Context.h"
#include "parser.h"
int main(int argc, char** argv) {
*stderr = *stdout;
con = new_Context();
yyin=fopen(argv[1],"rb");
ret = yyparse();
return ret;
}
in your parser.c
#ifdef __cplusplus
extern "C" {
#endif
C_Context *con;
#ifdef __cplusplus
}
#endif
That should do it.
wherever your new_context() is:
#include "parser.h"

I tried to call in c++ to function from C file to my cpp file but getting some errors:

I have a
c++ project dll type .
I added/created to this project a new item/file called it ENCODER.c
In the ENCODER.c i have some functions like:
void init()
{
}
void start()
{
}
Now i added/created a new header file called it: ENCODER.h
In this one i did:
namespace Encode
{
class Encode
{
public:
static __declspec(dllexport) void init();
};
}
Then in the cpp file i did:
#include <stdexcept>
using namespace std;
#include "stdafx.h"
#include "targetver.h"
#include "ENCODER.h"
extern "C" {
void myinit()
{
Encode::Encode::init();
}
}
In the cpp file i want that
Encode::Encode::init(); this init()
will do/activate the init() function i have in the C file !!
Now after doing all that i'm getting two errors:
LNK2019: unresolved external symbol "public: static void __cdecl Encode::Encode::init(void)" (?init#Encode#1#SAXXZ) referenced in function _myinit
LNK1120: 1 unresolved externals
First you need to declspec(export) the whole class, but it's more complex than that as you need to declspec(import) when using the class. Use the following macro and define BUILDING_MYLIBRARY when building the library (and ensure it's undefined when using the library)
#ifdef BUILDING_MYLIBRARY
#define MYLIBRARY_EXPORT __declspec(export)
#else
#define MYLIBRARY_EXPORT __declspec(import)
#endif
And then use it like this:
class MYLIBRARY_EXPORT Encode
{
...
};
Next ensure that any C functions that can be seen by C++ are declared extern "C" to turn off name mangling (the technology C++ uses to allow function overloading). So create a header (ENCODER.h) file for the C functions as follows, and include the header file in any C++ implementation file that wishes to use these functions:
#pragma once
#ifdef __cplusplus
extern "C"
{
#endif
void MYLIBRARY_EXPORT init();
void MYLIBRARY_EXPORT start();
#ifdef __cplusplus
} // extern "C"
#endif
and then implement these functions in a separate implementation (ENCODER.c) file (the use of MYLIBRARY_EXPORT is optional; it depends if you want to expose them from your .dll). When implementing them you don't need the extern "C" or the MYLIBRARY_EXPORT as long as the compiler has seen the header file, so include it:
#include "ENCODER.h"
void init()
{
...
}
void start()
{
...
}
Suggestion: Choose better names! The start() function already exists in the C runtime library, so how about initEncoder() and startEncoder()?

Referencing C functions in static library from C++

I have a static library of functions written in C. Let's say the header file is called myHeader.h and looks like:
#ifndef MYHEADER_H
#define MYHEADER_H
void function1();
void function2();
#endif
function1 and function2 aren't anything too special. Let's say they exist in a file called impl1.c which looks like:
#include "myHeader.h"
void function1() {
// code
}
void function2() {
// more code
}
All of the code mentioned so far is compiled into some static library called libMyLib.a. I'd rather not modify any of the code used to build this library. I also have a C++ header (cppHeader.h) that looks like:
#ifndef CPPHEADER_H
#define CPPHEADER_H
class CppClass {
private:
double attr1;
public:
void function3();
};
#endif
Then cppHeader.cpp looks like:
#include "cppHeader.h"
#include "myHeader.h"
// constructor
CppClass::CppClass(){}
void CppClass::function3() {
function1();
}
When I try to compile this, I get an error about an undefined reference to function1(). I believe that I've linked everything properly when compiling. I'm pretty rusty in my C++. I'm sure that I'm just doing something stupid. I hope that my simple example code illustrates the problem well enough.
Thanks in advance for any help!
The other solution (to the one suggested originally by Yann) is to surround your "C" header with:
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
Which saves you from having to remember to do:
extern "C" {
#include "foo.h"
}
every place you use foo.h
Make sure to use:
extern "C" {
#include "myHeader.h"
}
Or else the C++ compiler will generate symbol names which are name-mangled.