0

C++11 has sleep_for. But C standard doesn't have the equivalent.

I think I can write a wrapper to call such C++ functions from C.

And there are useful libraries like Boost Filesystem and Asio. These are more complicated but I can also write the wrapper.

Could it be reinventing the wheel? Could it be a bad idea?

cshu
  • 5,654
  • 28
  • 44
  • Have a look at http://stackoverflow.com/questions/264350/is-there-an-alternative-for-sleep-in-c – cup Sep 08 '15 at 05:25

2 Answers2

2

An issue with this is, if you want to write C wrappers which call Boost functions, what do you do if an exception is thrown? You basically have to swallow it in the caller before it reaches C, but its a bit awkward to properly report it to C then and there are quite a few types of exceptions.

Usually people use C instead of C++ when they specifically want the extra portability or cannot provide all the C++ dependencies for some reason. If you want to write a C program that uses boost::filesystem, why not just compile it as C++? You will have a lot less exception handling boiler plate code to write, and less can go wrong.

Chris Beck
  • 15,614
  • 4
  • 51
  • 87
  • Yes converting exceptions to codes is not elegant and inconvenient. I think I'll use wrappers when I already have a lot of C code and some simple C++ functions are just what I need. – cshu Sep 08 '15 at 05:06
2

zeroMQ does it that way. The library is written in C++, but the library API is a C interface. In principle, you hide classes in memory blocks of the object size and pass void* around. For a few simple function, e.g. sleep_for, you can just create a wrapper function. In your header, declare

extern "C" {void sleep_for(int duration);}

In your cpp-file, implement this in terms of std::this_thread::sleep_for.

sleep_for(int duration) {std::this_thread::sleep_for( std::chrono::milliseconds(duration);}

For classes, you need C function to create a new object, destruct it and of course to call member functions. For a class A, this could look as follows:

C header file "A_C_API.h":

extern "C" {
     enum {SIZE_OF_A = 4};
     typedef char[SIZE_OF_A] a_class;
     a_class initA(void* a, int x);
     void destructA(void* a);
     int callGet(void *a);
}

C++ source file:

class A {
public:
    A(int i): x{i} {}
    int get() const {return x;}
private:
    int x;
};

static_assert( SIZE_OF_A == sizeof(A), "size mismatch!");

void initA(void* a, int x) {
    new (a) A(x);
}

void destructA(void* a) {
    static_cast<A*>(a)->~A();        
}

int callGet(void *a) {
    return static_cast<A*>(a)->get();
}

In your C application, you can then

#include "A_C_API.h"
int main(int argc, char* argv[]) {
    a_class obj;
    initA(&obj);
    printf("%d", callGet(&obj) );
    destructA( &obj );
    return 0;
}

You will have to catch exceptions and convert them to some C error handling. You will also have to handle alignment issues on some platforms, especially SPARK platforms. I have omitted this for simplicity, but you can take a look at the zeromq header how to do this.

Jens
  • 9,058
  • 2
  • 26
  • 43