I’m writing a Unicode library for C as a personal exercise. Without the actual code, I have this:
typedef struct string {
unsigned long length;
unsigned *data;
} string;
// really simple stuff
string *upush(string *s, unsigned c) { ... }
// UTF-8 conversion
string *ctou(char *old) { ... }
char *utoc(string *old) { ... }
upush pushes the full Unicode code point c onto the end of s, reallocating as needed.
I can use the class like this, for example:
string a;
upush(&a, 0x44);
puts(utoc(&a));
Instead of having to use & to pass the reference to a function, is there a way I can write so that I can call:
string a;
upush(a, 0x44);
puts(utoc(a));
Or, do you think it’s just better to typedef string as a struct string pointer, not the struct itself, and always deal with struct string pointers?
Resolution? Thanks to Dummy00001, this is now my library’s general profile:
typedef struct string {
unsigned long length;
unsigned *data;
} string;
// really simple stuff
string *upush(string *s, unsigned c) { ... }
// UTF-8 conversions
string ctou(char *old) { ... }
char *utoc(string old) { ... }
Here are some examples:
string a = ctou("Hello, world");
upush(&a, '!');
puts(utoc(a));
I also learn, thanks to Doches, that in C++ (which is what I’ll write a wrapper for this library in), you can write the prototype like this to do implicit pass-by-reference:
string *upush(string &s, unsigned c);
For those who are interested, here’s my ongoing progress: http://delan.ath.cx/ulib
I personally prefer the
¬ation and use it (even in C++) to differentiate between the case of function which might modify its argument and the case of function accessing the struct as a const. IOW:In code above one sees immediately that
upush()takes&aand thus potentially modifies it. While theutoc()takes theaand doesn’t modify it.But the final decision how to make the interface largely depends on how you are going to manage the memory.
Make the symbol
stringbeing a pointer to an opaque structure, defined only inside the library itself. In public interface header:In internal header:
Interface functions would only accept the
stringwhich is pointer. Provide functions to create new string (calloc(1,sizeof(string *))) and to destroy it (free()). That way you would provide an interface to application which is consistent (developer doesn’t have to think about what is pointer what is not) and is also resilient to the library internal changes (since the struct’s structure only known inside the library itself).Downside is that one need to use dynamic memory management to allocate the puny struct:
malloc()/free()are fast, but it still fells like an overkill.