I love C so much, and I really want to hate sepples, but I can't help but think that generic programming in C is shit! Macros are no good for generic data structures, as they are clunky and blow out code size, nor are void pointers, as you need to allocate separate memory just to store an integer (don't stuff ints into pointers; zeros won't work on architectures where the null pointer constant is non-zero). I really want to write my data structure library in sepples, where templates allow type genericism without issue. What should I do, /prague/; what should I do?!
Macros are no good for generic data structures, as they are clunky and blow out code size
No, no, no. A fully generic type checked linked list can be written in 15 lines C macros. You must be a fucking retard, in which case I recommend you proceed with using sepples and fuck right off.
Name:
Anonymous2012-01-12 4:00
>>2
While that is true, I do not enjoy the idea of having no function call stack, nor do I enjoy the idea of having the entire code for each action on the structure copied again and again each time it is used. Now you can fuck right off.
>>5
C++ was born as a preprocessor for C with classes, Cfront.
Name:
Anonymous2012-01-12 4:49
>>6
So in other words, using sepples isn't such a sin after all, at least not the evil that /prague/ makes it out to be?
Name:
Anonymous2012-01-12 4:51
>>7
It's mostly the bloated standard library that people love to overuse, and of course the tendency to want to create dozens of classes just because it "feels good" (really?)
using sepples isn't such a sin after all
Oh it still is... and you'll spend eternity seeking memory leaks and mismanaged pointers in the nine threads of hell.
Name:
Anonymous2012-01-12 6:52
>>10
Well that sucks. How will I make data structures in C without macro hell or void pointers?
Name:
Anonymous2012-01-12 7:08
>How will I make data structures in C
Struct
Union
Typedef struct
Generics don't actually exists, they are just a layer that the programmer see and that the compiler strips away and does the casts and other things for you automatically
Name:
Anonymous2012-01-12 8:21
I wrote this up today, it's not very well tested but it has worked in the cases that I tested it.
Part 1 of 2:
#ifndef VECTOR_H__
#define VECTOR_H__
/*
* Please avoid side effects in the arguments
* to these macros.
*
* Note that these macros attempt to do the right
* thing when it comes to handling errors, generally
* they will return VECTOR_ERROR (default: NULL)
* casted to the type the vector carries upon error
* but more often than not the vector will be invalidated
* upon error.
*
* So if the vector is of type vector(int) then the error
* return will be (int) NULL, which might be a valid value
* for successful return depending on the input, therefore
* it is recommended that you define the VECTOR_ERROR macro
* to be some value that makes sense for your application.
*/
/**
* VECTOR_EMPTY_INITIALIZER
* Provides a valid constant sized empty
* vector of any type.
*/
#define VECTOR_EMPTY_INITIALIZER \
{NULL, NULL, NULL}
/**
* vector(type)
* Generic vector that provides
* - O(1)
* - append (amortized)
* - capacity
* - clear
* - is_empty
* - get
* - get_safe
* - pop
* - set
* - size
* - O(n)
* - insert
* - pop_first
* - prepend
* - remove
* - trim
* operations.
*/
#define vector(type) \
struct { \
type * base; \
type * head; \
type * end; \
}
/* returns the new size based
on VECTOR_SIZE_REFACTOR and
the old size*/
#define vector_newsize__(oldsize) \
((size_t) ((VECTOR_RESIZE_FACTOR + 1.0) * \
(oldsize)) + 1)
/**
* vector_append
* Adds element to the end of vector.
*
* @param (vector(type) *) vector in question
* @param (type) element to be added
* @return (type) element that was added
*/
#define vector_append(v, e) \
({ \
typeof(v) v__ = (v); \
typeof(*v__->base) e__ = (e); \
typeof(v__->base) b__ = v__->base; \
\
if (v__->head == v__->end) { \
ptrdiff_t cap__; \
cap__ = (v__->end - v__->base); \
\
b__ = realloc(v__->base, \
vector_newsize__(cap__) * \
sizeof(*v__->base)); \
\
if (b__ != NULL) { \
v__->base = b__; \
v__->head = b__ + cap__; \
v__->end = b__ + \
vector_newsize__(cap__); \
} \
} \
\
b__ == NULL ? \
(typeof(*v__->base)) VECTOR_ERROR : \
(*v__->head++ = e__); \
})
/**
* vector_capacity
* Returns the number of elements the current
* allocated underlying array may hold.
*
* @param (const vector(type) *) vector in question
* @return (ptrdiff_t) capacity of vector
*/
#define vector_capacity(v) \
({ \
typeof(v) v__ = (v); \
\
v__->end - v__->base; \
})
/**
* vector_clear
* Removes every element from vector
* and frees the underlying array.
*
* @param (vector(type) *) vector to clear
* @return (vector(type) *) the cleared vector
*/
#define vector_clear(v) \
({ \
typeof(v) v__ = (v); \
\
free(v__->base); \
v__->base = NULL; \
v__->head = NULL; \
v__->end = NULL; \
\
v__; \
})
/**
* vector_is_empty
* Returns whether the vector is empty.
*
* @param (const vector(type) *) vector in question
* @return (int) zero if the vector isn't empty and non-zero otherwise
*/
#define vector_is_empty(v) \
({ \
typeof(v) v__ = (v); \
\
v__->base == v__->head; \
})
/**
* vector_get
* Returns the element at a certain
* position in the vector without
* removing it.
*
* @param (const vector(type) *) the vector in question
* @param (int) index of element in vector
* @return (type) the element at index in vector
*/
#define vector_get(v, i) \
((v)->base[(i)])
/**
* vector_get_safe
* Returns the element at a certain
* position in the vector without
* removing it.
*
* This returns NULL casted to type
* upon error.
*
* @param (const vector(type) *) the vector in question
* @param (int) index of element in vector
* @return (type) the element at index in vector
*/
#define vector_get_safe(v, i) \
({ \
typeof(v) v__ = (v); \
int i__ = (i); \
\
i__ < vector_size(v) ? \
v__->base[i__] : \
(typeof(*v__->base)) VECTOR_ERROR; \
})
/**
* vector_insert
* Inserts an element at a certain position
* in vector without removing any elements.
*
* @param (vector(type) *) the vector in question
* @param (int) the index of the new element
* @param (type) the element to be added
* @return (type) the added elemenet
*/
#define vector_insert(v, i, e) \
({ \
typeof(v) v__ = (v); \
typeof(*v__->base) e__ = (e); \
typeof(*v__->base) l__; \
int i__ = (i); \
ptrdiff_t size__ = vector_size(v); \
\
l__ = (typeof(*v__->base)) VECTOR_ERROR; \
\
if (i__ < 0) \
l__ = l__; \
else if (i__ == size__) \
l__ = vector_append(v, e); \
else if (i__ < size__) { \
typeof(*v__->base) p__; \
int j__; \
\
p__ = v__->base[size__-1]; \
\
for (j__ = size__-1; j__ > i__; j__--) \
v__->base[j__] = v__->base[j__-1]; \
\
v__->base[i__] = e__; \
\
l__ = vector_append(v, p__) == \
(typeof(*v__->base)) VECTOR_ERROR ? \
l__ : \
e__; \
} else \
l__ = l__; \
\
l__; \
})
/**
* vector_pop
* Removes and returns the element
* at the end of the vector.
*
* @param (vector(type) *) vector in question
* @return (type) the removed element
*/
#define vector_pop(v) \
({ \
typeof(v) v__ = (v); \
\
v__->head == v__->base ? \
(typeof(*v__->base)) VECTOR_ERROR : \
*--v__->head; \
})
/**
* vector_pop_first
* Removes and returns the first
* element of the vector.
*
* @param (vector(type) *) vector in question
* @return (type) the removed element
*/
#define vector_pop_first(v) \
({ \
typeof(v) v__ = (v); \
typeof(*v__->base) l__; \
ptrdiff_t size__; \
\
size__ = vector_size(v); \
\
if (size__ > 1) { \
int i__; \
\
l__ = v__->base[0]; \
\
for (i__ = 0; i__ < size__-1; i__++) \
v__->base[i__] = v__->base[i__+1]; \
\
v__->head -= 1; \
} else { \
l__ = vector_pop(v); \
} \
\
l__; \
})
/**
* vector_prepend
* Adds element to the front of vector.
*
* @param (vector(type) *) vector in question
* @param (type) element to be added to vector
* @return (type) element that was added
*/
#define vector_prepend(v, e) \
({ \
typeof(v) v__ = (v); \
typeof(*v__->base) e__ = (e); \
typeof(*v__->base) l__; \
ptrdiff_t size__ = vector_size(v); \
\
if (size__ > 0) { \
int i__; \
\
l__ = v__->base[size__-1]; \
\
for (i__ = size__ - 1; i__ > 0; i__--) \
v__->base[i__] = v__->base[i__-1]; \
\
v__->base[0] = e__; \
} else { \
l__ = e__; \
} \
\
vector_append(v, l__) == \
(typeof(*v__->base)) VECTOR_ERROR ? \
(typeof(*v__->base)) VECTOR_ERROR : \
e__; \
})
/**
* vector_remove
* Removes and returns an element at a
* certain position in vector.
*
* @param (vector(type) *) vector in question
* @param (int) index of element
* @param (type) the removed element
*/
#define vector_remove(v, i) \
({ \
typeof(v) v__ = (v); \
typeof(*v__->base) l__; \
int i__ = (i); \
ptrdiff_t size__ = vector_size(v); \
\
l__ = (typeof(*v__->base)) VECTOR_ERROR; \
\
if (i__ < 0) \
l__ = l__; \
else if (i__ == size__-1) \
l__ = vector_pop(v); \
else if (i__ < size__) { \
int j__; \
\
l__ = v__->base[i__]; \
\
for (j__ = i__; j__ < size__-1; j__++) \
v__->base[j__] = v__->base[j__+1]; \
\
v__->head -= 1; \
} else \
l__ = l__; \
\
l__; \
})
/**
* vector_set
* Sets the element at a certain position
* in the vector and removes the old element.
*
* @param (vector(type) *) the vector in question
* @param (int) index of new element
* @param (type) element to be added
* @return (type) element that was added
*/
#define vector_set(v, i, e) \
({ \
typeof(v) v__ = (v); \
typeof(*v__->base) e__ = (e); \
typeof(*v__->base) l__; \
int i__ = (i); \
ptrdiff_t size__; \
\
size__ = vector_size(v); \
l__ = (typeof(*v__->base)) VECTOR_ERROR; \
\
if (i__ < 0) \
l__ = l__; \
else if (i__ < size__) \
l__ = (v__->base[i__] = e__); \
else if (i__ == size__) \
l__ = vector_append(v, e); \
else \
l__ = l__; \
\
l__; \
})
/**
* vector_size
* Returns the current number of elements
* in the vector.
*
* @param (const vector(type) *) vector in question
* @return (ptrdiff_t) number of elements in vector
*/
#define vector_size(v) \
({ \
typeof(v) v__ = (v); \
\
v__->head - v__->base; \
})
/**
* vector_trim
* Resizes the underlying array so only the
* elements currently in vector fits.
*
* @param (vector(type) *) the vector in question
* @return (vector(type) *) the trimmed vector
*/
#define vector_trim(v) \
({ \
typeof(v) v__ = (v); \
typeof(v__->base) b__; \
ptrdiff_t size__ = vector_size(v); \
\
b__ = realloc(v__->base, \
size__ * sizeof(*v__->base)); \
\
if (b__ != VECTOR_ERROR) { \
v__->base = b__; \
v__->head = b__ + size__; \
v__->end = b__ + size__; \
} \
\
b__ == VECTOR_ERROR ? \
VECTOR_ERROR : \
v__; \
})
I was a little over-eager near the end so some of the NULLs were turned into VECTOR_ERRORs, the comparisons with b__ should be NULL and not VECTOR_ERROR.
Also this is not macro hell, this is macro heaven.
Enjoy wondering why your 500 lines equates to 50000+ line C file won't compile when you try to use that in any type of project that makes heavy use of said data structure.
how does that work for char and int? They are different sizes.
Name:
Anonymous2012-01-12 10:13
>>1
You should try C++. It supports templates which would allow you to do what you want. It also has STL that has some nice standard containers. STL is easily better than Java or C# containers.
>>24
I bet your mom must be proud oc that piece of C code.
Name:
Anonymous2012-01-12 11:56
So use C++ then, and pick and choose your style of programming. C++ doesn't really remove anything of value from C, and it adds a ton of features, at least a handful of which you may find useful. Also, it's a hell of a lot safer than these posts:
There's no real benefit to using C over C++ except for a slight performance boost (which really is only slight), it's just that C programmers hate C++ programming practices, which you don't have to use (it's just that C++ programmers consider them safer than the C alternative, which is >>14-15)
Name:
Anonymous2012-01-12 11:57
>>28
I showed it to her and she said she didn't understand.
>>24
By the way, I think you meant __typeof__ and not typeof.
Name:
Anonymous2012-01-12 12:00
>>31
Not the guy who made it but it's clearly not for use in ISO C programs.
Name:
Anonymous2012-01-12 12:02
>>31
This is your daily reminder that the statement every subset of a countable set is also countable is absolutely true and never fails under any conditions.
Keep denying the truth you mental midget, I'm sure it'll change one day. Oh wait...
Name:
Anonymous2012-01-12 12:04
>>27
that's another way to reply to what >>25 said, yes.
>>29
c isn't faster. c++ wasn't designed in such a way that you could never write code that was fast as c code. it's all down to the implementation.
>>3
There is no ``function call stack'' in C so you are wrong right from the start, and in any case, if you are worried about a little bit of macro replacement you shouldn't be using C in the first place. (You do know how #include works, right?)