With heavy use of macros,, care should be applied to insure exactly one use of a macro argument as the macro arguments could be complex and have side effects which only should be evaluated once.
//#define ary_attach(ary, nbuf, nlen, nalloc) \ // do { \ // ary_freebuf(&(ary)->s); \ // (ary)->s.buf = (ary)->buf = nbuf;\ // ... #define ary_attach(ary, nbuf, nlen, nalloc) \ do { \ struct aryb *ary__ = ary; // add \ ary_freebuf(&ary__->s); \ ary__->s.buf = ary__->buf = nbuf; \ ...Avoid magic numbers like 32. Why 32?
// static const size_t snprintf_bufsize = 32; // Maximum buffer size of string version of `int` log10(bitwidth) // Other formula are more precise, but better than guessing buffer needs. static const size_t snprintf_bufsize = sizeof(int)*CHAR_BIT/3 + 3; int ary_cb_inttostr(char **ret, const void *elem) { if (!(*ret = ary_xrealloc(NULL, snprintf_bufsize, 1))) return -1; return snprintf(*ret, snprintf_bufsize, "%d", *(int *)elem); }As
free(NULL)is OK, IMO, any free-like function should also handleNULL.void ary_freebuf(struct aryb *ary) { if (ary == NULL) return; // add if (ary->len && ary->dtor) {ary.cshould include files likestrcmp.hand not count on#include "ary.h"to have included them.Consider simpler code, as below and in other places.
// size_t seplen = sep ? strlen(sep) : 0, i, len; size_t seplen = sep ? strlen(sep) : 0; size_t i, len;Without clear code understanding, I have a bit concern about
strbuf.buf[strbuf.len - 1]. Shouldstrbuf.len == 0, disastrous result would occur.Uncertain: Comments on # lines is not portable. I'll have to research this.
#endif /* ARY_H */Be careful about
ary_xrealloc(), which callsrealloc(). Shouldary->len == 0, returnNULLis not an out-of-memorybuf = ary_xrealloc(ary->buf, ary->len, ary->sz); // if (!buf) return 0; if (buf == NULL && ary->len > 0 && ary->sz > 0) return 0;