3 ms·
This is what the macros expand to. From: $ cat test.c #define ARRAY(T,S) T S;size_t S##_length;size_t S##_capacity #define ARRAY_INIT(S) \
by gravypod 10y ago
This is what the macros expand to.
From:
$ cat test.c
#define ARRAY(T,S) T S;size_t S##_length;size_t S##_capacity
#define ARRAY_INIT(S) \
do { \
S=NULL; \
S##_length=0; \
S##_capacity=0; \
} while(0)
#define ARRAY_DESTROY(S) \
do { \
Array_Free(S); \
ARRAY_INIT(S); \
} while(0)
#define ARRAY_ADD(S,X) \
do { \
if(S##_length>=S##_capacity) \
S=Array_Grow(S,sizeof &S,&S##_length,&S##_capacity); \
S[S##_length++]=(X); \
} while(0)
void Array_Free(void *p) {
free(p);
}
void *Array_Grow(void *base,size_t stride,size_t *length,size_t *capacity) {
*capacity+=*capacity/2;
*capacity=MAX(*capacity,MAX(MIN_CAPACITY,*length));
return realloc(base,*capacity*stride);
}
#define ARRAY_PARAMS(T,S) T *S,size_t S##_length,size_t S##_capacity
#define ARRAY_ARG(S) S,S##_length,S##_capacity
void test(ARRAY_ARG(p), ARRAY_ARG(a))
{
}
int main() {
ARRAY(int, myarray);
ARRAY(int, ourarray);
test(ARRAY_ARG(myarray), ARRAY_ARG(ourarray));
}
To:
$ gcc -E test.c
# 1 "test.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 /usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "test.c"
# 22 "test.c"
void Array_Free(void *p) {
free(p);
}
void *Array_Grow(void *base,size_t stride,size_t *length,size_t *capacity) {
*capacity+=*capacity/2;
*capacity=MAX(*capacity,MAX(MIN_CAPACITY,*length));
return realloc(base,*capacity*stride);
}
void test(p,p_length,p_capacity, a,a_length,a_capacity)
{
}
int main() {
int myarray;size_t myarray_length;size_t myarray_capacity;
int ourarray;size_t ourarray_length;size_t ourarray_capacity;
test(myarray,myarray_length,myarray_capacity, ourarray,ourarray_length,ourarray_capacity);
}
Looks like fairly reasonable code.
Edit: I would like to see it take a type in the Params and a __typeof__ while passing the args to make sure you know what is going where.
- to3m 10y agoThanks for trying it out - my post was assembled by copying bits out of the (rather gnarlier) code that I actually used, so I'm glad it mostly survived the process ;) Interesting point about the type checking; my thinking was that the compiler could check they matched, and that this would suffice - and sure enough it worked absolutely fine in practice. But now that I'm made to think about it again, I think it's probably still not quite good enough to be perfect, because you could do this: void f(ARRAY_PARAMS(const char *,*xs)) { ARRAY_ADD(*xs,"fred"); } ... ARRAY(char *,xs); ARRAY_INIT(xs); f(&xs); And now you've got a char * that points to a const string. Erm... that's not good! EDIT: maybe I see what you're getting at with ARRAY_ARG now. The intention is that you use ARRAY_PARAMS to generate the text for the function declaration or definition (that's why it has the type in it), and ARRAY_ARG to generate the text for the code where you pass one to a function so declared (that's why it's just 3 names - they're intended to be expressions, not names for function parameters). That means test should (?) be like this: void test(ARRAY_PARAMS(int, p), ARRAY_PARAMS(int, a)) { } Hopefully that makes sense. Maybe they'd have been better off with the common C terminology of formal and actual parameters. Then you'd have ARRAY_FORMAL_PARAMS for ARRAY_PARAMS, and ARRAY_ACTUAL_PARAMS for ARRAY_ARG.