Skip to content

Instantly share code, notes, and snippets.

@ShonFrazier
Last active May 29, 2017 13:43
Show Gist options
  • Save ShonFrazier/16f46834355d9f6a28e3243497914142 to your computer and use it in GitHub Desktop.
Save ShonFrazier/16f46834355d9f6a28e3243497914142 to your computer and use it in GitHub Desktop.
Poco - Wrapping UUIDGenerator and UUID classes in C-friendly code
#include <stdio.h>
#include "PocoUUIDWrap.h"
int main(int argc, const char * argv[])
{
PocoUUIDGenerator *generator = PocoUUIDGeneratorCreate();
PocoUUID *uuid = PocoUUIDGeneratorCreateRandom(generator);
const char *uuid_str = PocoUUIDToString(uuid);
printf("UUID: %s\n", uuid_str);
PocoUUIDFree(uuid);
uuid = NULL;
PocoUUIDGeneratorFree(generator);
generator = NULL;
return 0;
}
#include "PocoUUIDWrap.h"
#include <Poco/UUID.h>
#include <Poco/UUIDGenerator.h>
using Poco::UUID;
using Poco::UUIDGenerator;
PocoUUID *PocoUUIDCreate(void)
{
// Get the new object pointer...
UUID *_uuid = new UUID();
// Cast it to the correct struct pointer type and return.
return (PocoUUID *)_uuid;
}
void PocoUUIDFree(PocoUUID *uuid)
{
// Cast the struct pointer back to a C++ object pointer...
UUID *_uuid = (UUID *)uuid;
// ...and destroy it. The caller should set the variable to NULL to avoid accessing invalid memory.
delete _uuid;
}
const char *PocoUUIDToString(PocoUUID *uuid)
{
// Cast to the C++ type...
UUID *_uuid = (UUID *)uuid;
// Return the C-string representation
return _uuid->toString().c_str();
}
PocoUUIDGenerator *PocoUUIDGeneratorCreate(void)
{
UUIDGenerator *_uuidGenerator = new UUIDGenerator();
return (PocoUUIDGenerator *)_uuidGenerator;
}
void PocoUUIDGeneratorFree(PocoUUIDGenerator *uuidGenerator)
{
UUIDGenerator *_uuidGenerator = (UUIDGenerator *)uuidGenerator;
delete _uuidGenerator;
}
PocoUUID *PocoUUIDGeneratorCreateRandom(PocoUUIDGenerator *uuidGenerator)
{
UUIDGenerator *_uuidGenerator = (UUIDGenerator *)uuidGenerator;
UUID _uuid = _uuidGenerator->createRandom(); //Stack-allocated - DO NOT RETURN ADDRESS
// Make a new copy...
UUID *_puuid = new UUID(_uuid);
// ...and return THAT address, cast to the proper type.
return (PocoUUID *)_puuid;
}
#ifndef PocoUUIDWrap_hpp
#define PocoUUIDWrap_hpp
#ifdef __cplusplus
// Make sure the (C++) compiler doesn't perform C++ name mangling on these symbols; "Use C linkage"
#define EXTERNC extern "C"
#else
// The C compiler already expects C linkage (actually specifying linkage is an error to a C compiler)
#define EXTERNC
#endif
// Because C has no concept of C++ objects, and because it's far too complex to create a complete
// struct to represent a C++ object ...
// Define opaque structs to represent our wrapped C++ objects.
EXTERNC typedef struct PocoUUID PocoUUID;
EXTERNC typedef struct PocoUUIDGenerator PocoUUIDGenerator;
// And because the structs are opaque, we have to work with pointers. Passing a copy of a *complete*
// struct type is possible, but we will never complete these structs.
// Ask for creation of a new UUID
EXTERNC PocoUUID *PocoUUIDCreate(void);
// Free a UUID
EXTERNC void PocoUUIDFree(PocoUUID *uuid);
// Get a C-string representation of a UUID
EXTERNC const char *PocoUUIDToString(PocoUUID *uuid);
// Ask for creation of a new UUIDGenerator
EXTERNC PocoUUIDGenerator *PocoUUIDGeneratorCreate(void);
// Free a UUIDGenerator
EXTERNC void PocoUUIDGeneratorFree(PocoUUIDGenerator *uuidGenerator);
// Generate a random UUID
EXTERNC PocoUUID *PocoUUIDGeneratorCreateRandom(PocoUUIDGenerator *uuidGenerator);
#endif /* PocoUUIDWrap_hpp */
@ShonFrazier
Copy link
Author

To use a C++ class from C, wrap the classes and methods in C-friendly grammar: declare an opaque struct type to represent each class; allocate C++ objects with 'new', cast the pointer to a pointer to the opaque struct type, and return it; cast the struct pointer to the original class type to call methods on it; free with 'delete'; make sure to indicate C linkage on the new functions. In the code above, you'll also see returning a C-string instead of a std::string, as well as copying a stack-allocated object to a heap allocated object ('new') to avoid returning the address of a stack object.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment