I wrote this small example piece of OOP being implemented in pure C. I wanted it to be reviewed for the following points:
- Portability
Performance
And especially
- Usability
- "How does it look"
Implementation:
typedef char XCFString;
struct XCFStringStatic {
void *(*initWithCString)(const char *);
};
struct XCFStringClass {
void (*release)(void);
size_t length;
char *value;
};
// Pointer to current class
XCFString **XCFStringCTX = NULL;
// Release method
void XCFString__release(void)
{
assert(XCFStringCTX != NULL);
XCFString *ctx = *XCFStringCTX;
free(((char *)ctx) - sizeof(struct XCFStringClass));
}
// Init method
void *XCFString__initWithCString(const char *str)
{
size_t str_len = strlen(str);
struct XCFStringClass *data = malloc(sizeof(* data) + str_len + 1);
if (!data) return NULL;
char *str_val = ((char *)data) + sizeof(* data);
memcpy(str_val, str, str_len + 1);
data->length = str_len;
data->value = str_val;
data->release = XCFString__release;
return data->value;
}
struct XCFStringStatic XCFStringStatic = {.initWithCString = XCFString__initWithCString};
#define priv_getMacroName1(_0, _1, macroName, ...) macroName
#define getMacroName1(macroName, args...) priv_getMacroName1(_0, ##args, macroName ## _1, macroName ## _0)(args)
#define XCFString_0() (XCFStringStatic)
#define XCFString_1(_var) (XCFStringCTX=&(_var), ((struct XCFStringClass *)(((char *)_var) - sizeof(struct XCFStringClass))))
// Switch between XCFString_0 and XCFString_1, GNUC only
#define XCFString(args...) getMacroName1(XCFString, ##args)
Test code for main.c
int main(int argc, const char **argv)
{
// Pointer to our String class
XCFString *string = NULL;
// Initialize string with "Hallo Welt!"
string = XCFString().initWithCString("Hallo Welt!");
// Print it as if it were a normal string
fprintf(stderr, "String : %s\n", string);
fprintf(stderr, "Length : %zu\n", strlen(string));
// Get the properties from the string
fprintf(stderr, "Str.value : %s\n", XCFString(string)->value);
fprintf(stderr, "Str.length : %zu\n", XCFString(string)->length);
// Release the string
XCFString(string)->release();
}
clang
says "named variadic macros are a GNU extension" and goes on to fail to build. \$\endgroup\$