#Macro Based Dynamic Array in C
65 messages · Page 1 of 1 (latest)
What are some issues with my implementation?
looks pretty cool
there is define_array but not declare_array, so this cannot have external linkage
seeing that that's the case, then all the functions should be static
and honestly it would make more sense to use external tools for codegen at this point, if basically the entire file has to be a macro
I added declare_array
What tools would you suggest using?
string replace in basically any language would work well
this is unironically a better solution than C macros
if you just replaced every instance of <T> with the type of the array, you'd have much more readable code
just make CMake or Make generate these files using a two-liner python script and off you go
thanks I'll look into it
@keen isle You can look at my implementation here
https://github.com/apaz-cli/pgen/blob/master/src/list.h
Using the __auto_type builtin is unnecessary, it can be done in standard C.
Also a reasonable solution
Although you also would have to separately declare_list_add(int) and define_list_add(int) every list_add(int)(i) before you use it.
Which is doable, but a whole lot of work.
its not too bad
#define define_array(T) \
define_array_header(T); \
define_array_alloc(T); \
define_array_push(T); \
define_array_pop(T); \
define_array_free(T); \
define_array_reserve(T); \
define_array_clear(T); \
define_array_erase(T); \
define_array_insert(T); \
define_array_shrink(T); \
define_array_concat(T); \
define_array_apply(T); \
define_array_take_back(T); \
define_array_trash(T); \
define_array_sort(T); \
i do this and its just one line
Fair enough
though it will increase binary size
Unless you pass through an option to make them static
i was told inline is a suggestion to the compiler
A suggestion that most compilers completely ignore
huh will they still optimize if the function should be inlined
like if you dont include inline
All popular compilers will inline anyway, unless it needs to be exported as a symbol, in which case it may as well just call.
Unless the function is small enough that more code would be generated by observing the calling conventions than by inlining.
That's roughly the heuristic that's used.
Compilers want to output as few instructions as possible.
how would one do it in standard C?
You make a variable of type T?
And you generate the type of the array from macros also
You can look at what I posted for how I do it.
#define LIST_DEFINE(type) \
static inline list_##type list_##type##_new() { \
list_##type nl; \
nl.buf = NULL; \
nl.len = 0; \
nl.cap = 0; \
return nl; \
}
ah
Then you can just say list_type outside the macro.
I have an Array_Header so it would be int_Array_Header maybe i should reconsider the name.
Yes, why not Array_Header_int
or just array_int lol
Is there any way to get around multiword types other than a typedef
perferably one that would allow code like this
array_push_s(p, &k, Package *);
where i can just use the types as is without a typedef
I guess using code generation tool would allow that among other things
Nope, just use a typedef
For example, typedef char* cstr; LIST_DEFINE(cstr)
You can freely assign to/from char*, compiler doesn't care.
In my implementations I have macro vector(T) that will make anonymous structure with T*, length and capacity and all myself functions takes vector(void*), also I have lot of macros because I need to pass sizeof(*vec->data) to nearly every function
I had another version where I did:
typedef type* list_type;
// Technically illegal, breaks type-based aliasing analysis,
// but supported by all popular compilers
size_t list_len_type(list_type l) { return *(((size_t*)(char*)l) - 1); }
size_t list_cap_type(list_type l) { return *(((size_t*)(char*)l) - 2); }
list_type list_init_type(size_t cap) {
char* cptr = (char*)malloc(cap * sizeof(type) + sizeof(size_t) * 2);
*(((size_t*)cptr) - 1) = 0;
*(((size_t*)cptr) - 2) = cap;
return (list_type)cptr;
}
/* Other methods*/
int main() {
list_type l = list_init_type(5);
for (size_t i = 0; i < 10; i++)
list_add_type(l, (type){...});
for (size_t i = 0; i < list_len_type(l); i++)
print_type(l[i]);
}
The benefit of doing it this way is that you can dereference the list directly.
l[i]
The downside is that whenever you type .add(), the array may need to be reallocated. Which is bad, because it invalidates all other references to the list.
I moved away from this technique, because writing l.buf[i] or l->buf[i] isn't too bad.