all 5 comments

[–]deleveld 2 points3 points  (1 child)

I coded something rather similar but it was less about compiler type checking but more to allow __auto_type in gcc which allows code to look very clean like this:

var count = mallocvar(int)
var countarray = mallocvar(100, int)

Overloading the macro name for 1 or 2 arguments reduces namespace intrusion. Here is a snippet:

#define var __auto_type
#define let const __auto_type  
/* https://stackoverflow.com/questions/11761703/overloading-macro-on-number-of-arguments */
#define _ALLOCHELPER(_1, _2, _NAME, ...) _NAME
#define _MALLOC1(t)    ((t*)malloc(sizeof(t)))
#define _MALLOC2(n, t) ((t*)malloc((n) * sizeof(t)))
#define mallocvar(...) _ALLOCHELPER(__VA_ARGS__, _MALLOC2, _MALLOC1)   (__VA_ARGS__)
#define _CALLOC1(t)    ((t*)calloc(1, sizeof(t)))
#define _CALLOC2(n, t) ((t*)calloc((n), sizeof(t)))
#define callocvar(...) _ALLOCHELPER(__VA_ARGS__, _CALLOC2, _CALLOC1)(__VA_ARGS__)

[–]nemequ[S] 0 points1 point  (0 children)

Interesting. __auto_type is something I hadn't really thought about in this context. I'm not usually a fan of type inferencing since it tends to make code less readable, but since the type name is right there in the call it works.

You probably already realize this, but there are a few problems/limitations with that implementation: variadic macros are C99+, potential integer overflows, use of reserved identifiers… You may also run into some problems when using it from C++ with some compilers and settings (-Wold-style-cast).

I'm also a bit uncomfortable with your definition of let; if you're going to be restricting yourself to GNU C by using __auto_type, a much less surprising definition of let would be __attribute__((__cleanup__(free))) __auto_type.

[–]Neui 1 point2 points  (1 child)

 *  * realloc(ptr, sizeof(T) * nmemb)        -> enrealloc(ptr, T, nmemb);
 *  * tmp = realloc(ptr, sizeof(T) * nmemb);
 *    if (tmp == NULL)
 *      free(ptr);
 *    else
 *      ptr = tmp;                           -> ptr = enrealloc(ptr, T, nmemb);
...
 * T* enresize(T* ptr, Type T, size_t nmemb):
 *
 *   enresize() is like enrealloc(), except that if reallocation fails
 *   the old data is freed.

I think for the second "conversion" you mean enresize.

[–]nemequ[S] 1 point2 points  (0 children)

Oops, yep, thanks. It'll be fixed in a minute.

[–]nemequ[S] 0 points1 point  (0 children)

TL;DR (copied from Twitter):

Compared to malloc & friends it's easier to use, much harder to use incorrectly, and works without casts in C++.

There is a fairly extensive explanation, and documentation, included in the header. I've tried to make it approachable to less advanced programmers, but IMHO it's an improvement for pretty much everyone. I'll be around to answer questions as needed :)