4 ms·
Weird implementation. If you want an magical 'append' function, use a stack, or a linked list. There's no reason you'd want to 'append' to an array. (Imagine
by shadowmint 14y ago
Weird implementation. If you want an magical 'append' function, use a stack, or a linked list.
There's no reason you'd want to 'append' to an array.
(Imagine the situation you remove an item in the middle; what is append supposed to do now? What is remove supposed to do? The append function in this example is basically just 'make_me_bigger')
Still, if you did want to, I'd be doing this to reduce verbosity:
#define _V(a) ((int *) &a)
struct Vec {
int *data;
int size;
int offset;
}
struct v;
_V(v)[5] = 10;
int value = _V(v)[5];
You only need two special calls; append() (aka. make this array longer) and free().
- klodolph 14y agoThe _V() macro horrifies me. It's not remotely safe, nor is it even slightly correct. From least important to most important, 1. The _V() macro is in the compiler namespace, which is a no-no. You can't legally use identifiers that start with underscores which are followed by upper-case ASCII characters. 2. The _V() macro performs no type checking. It takes any addressable object as an argument. You can't do _V(3), but you can do _V(printf). 3. The _V() macro scribbles on memory. #define V(a) ((int *) &a) struct Vec { int *data; int size; int offset }; struct v v; // don't forget the second v _V(v)[5] = 10; // this scribbles on the stack What the macro does is take the address of the Vec structure (or anything else addressable, since it does no type checking) and pretends that that address is the address of an integer array. The stack: | | +------------+ | int *data; | <---- &v, (int *) &v +------------+ | int size | +------------+ | int offset | +------------+ | <stack> | +------------+ | <stack> | +------------+ | <stack> | <---- &_V(v)[5] scribbles here +------------+ | | On a 32-bit system, _V(v)[5] is three words after the Vec structure, somewhere on your stack.
- shadowmint 14y agoMy bad, you are correct, that's not quite right. You'd do it like this: #include <stdio.h> #include <stdlib.h> #define _V(a) (*((int **) &a)) struct Vec { int *data; int size; }; int main (int argc, char** argv) { struct Vec v; v.data = (int *) malloc(sizeof(int) * 10); v.size = 10; printf("%lx <-- actual\n", (long) v.data); printf("%lx <-- cast\n", (long) _V(v)); for (int i = 0; i < 10; ++i) { _V(v)[i] = i; } for (int i = 0; i < 10; ++i) { printf("%d was: %d\n", i, _V(v)[i]); } free(v.data); return 0; } ... roar:~$ valgrind ./a.out ==30957== Memcheck, a memory error detector ==30957== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al. ==30957== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info ==30957== Command: ./a.out ==30957== 51f1040 <-- actual 51f1040 <-- cast 0 was: 0 1 was: 1 2 was: 2 3 was: 3 4 was: 4 5 was: 5 6 was: 6 7 was: 7 8 was: 8 9 was: 9 ==30957== ==30957== HEAP SUMMARY: ==30957== in use at exit: 0 bytes in 0 blocks ==30957== total heap usage: 1 allocs, 1 frees, 40 bytes allocated ==30957== ==30957== All heap blocks were freed -- no leaks are possible ==30957== ==30957== For counts of detected and suppressed errors, rerun with: -v ==30957== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
- klodolph 14y agoSo, what's the point? Why not just use... v->data[i] = x; This is, drum roll... type checked by the compiler, unlike _V(). P.S. Stop casting the result of malloc(), it makes you look like you're trying to write C++. There's no good reason for it in C, and there's a good reason not to do it (because it can mask an error if you forget to include <stdio.h>). For this reason, and because it looks like you want generics, it sounds like you want to write C++. Why not write C++? Then you can just overload operator[] and go on your merry little way, without having to circumvent the type checker with macros.
- shadowmint 14y agoWho said anything about generics? You could just #define v(a) (a->data) and be done with it, it's true.