7
\$\begingroup\$

I've seen few similar post about dynamic array inC released asmacros, but I tried a new approach to make it looks more like a template, wrapped in a big macros. However I need a review for suggestions or improvements also. Here is the trivial implementation:

dynarray_t.h

#ifndef DYNARRAY_T_H#define DYNARRAY_T_H#include <stdlib.h> /* malloc, calloc, realloc *///in case no initsize is 0 or less we will assert#define DARRAY(T, N, INITSIZE, MOD)                                 \static const char __attribute__((unused))                           \            N##_sassertsizeless[INITSIZE <=0 ? -1 : 1];             \    typedef struct                                                  \    {                                                               \        size_t size, count;                                         \        T* pData;                                                   \    } N##_t;                                                        \    MOD N##_t* self_##N;                                            \                                                                    \    static N##_t* N##_t##_init(void)                                \    {                                                               \        N##_t* pN = (N##_t*)malloc(sizeof(N##_t));                  \        if (!pN) return 0x00;                                       \        else {                                                      \            pN->pData = (T*)calloc(INITSIZE, sizeof(T));            \            if (!pN->pData) { free(pN); return 0x00; }              \            else {                                                  \                pN->count = 0;                                      \                pN->size = INITSIZE;                                \                return pN; }                                        \            }                                                       \    }                                                               \                                                                    \    static void N##_t##_wiffull(N##_t* _this)                       \    {                                                               \        if (!(_this->count < _this->size-1)) {                      \        T* t = (T*)realloc(_this->pData,                            \                            sizeof(T)* _this->size * 2);            \        if (t) {                                                    \            _this->pData = t;                                       \            _this->size *= 2;                                       \            }                                                       \        }                                                           \    }                                                               \                                                                    \    static void N##_t##_resizeto(N##_t* _this, size_t ns)           \    {                                                               \        if (ns > _this->size-1) {                                   \        T* t = (T*)realloc(_this->pData,                            \                            sizeof(T)* ns * 2);                     \        if (t) {                                                    \            _this->pData = t;                                       \            _this->size = ns * 2;                                   \            }                                                       \        }                                                           \    }                                                               \                                                                    \    static void N##_t##_add(T item, N##_t* _this)                   \        {                                                           \            N##_t##_wiffull(_this);                                 \            *(_this->pData+_this->count) = item;                    \            _this->count++;                                         \        }                                                           \                                                                    \    static T* N##_t##_getat(unsigned int idx, N##_t* _this)         \    {                                                               \        if (idx < _this->count)                                     \            return &_this->pData[idx];                              \        else return 0x00;                                           \    }                                                               \                                                                    \    static void N##_t##_cleanup(N##_t* _this)                       \    {                                                               \        if (_this) {                                                \            if (_this->pData) free(_this->pData);                   \            _this->pData = 0x00;                                    \            free(_this);                                            \            _this = 0x00;                                           \        }                                                           \    }                                                               \    static void N##_t##_add_at(T item, size_t idx, N##_t* _this)    \        {                                                           \            N##_t##_resizeto(_this, idx);                           \            *(_this->pData+idx) = item;                             \            _this->count++;                                         \        }                                                           \#endif // DYNARRAY_T_H

And some simple example usage:

#include "dynarray_t.h"#include <stdio.h>#include <stdlib.h>#include <string.h>#define BUFF_SZ 83typedef struct _str_t {    char data[BUFF_SZ];} str_t;DARRAY(str_t, readBuff, 101,);int main(void){    int i;    self_readBuff = readBuff_t_init(); // init    for(i=0; i < 100; i++) { // fill        str_t t = {{0}};        snprintf(t.data, sizeof (t.data), "Test line [%d]", i);        readBuff_t_add(t, self_readBuff);    }    int s = self_readBuff->size;    for(i=0; i < self_readBuff->size; i++) { // read element at(index)        printf("%s\r\n", readBuff_t_getat(i, self_readBuff)->data);    }    readBuff_t_cleanup(self_readBuff);    return  0;}

Also please refer toC language only! Not interested in talking forC++, I am quite aware how to work it ontemplate. I need something similar forC, so please give me an advice for design, or spot pitfalls if any.

askedAug 1, 2020 at 16:09
Ilian Zapryanov's user avatar
\$\endgroup\$
2
  • \$\begingroup\$Why are you force-appending the_t to the type? Shouldn't the user decide whether they want areadBuff or areadBuff_t?\$\endgroup\$CommentedAug 2, 2020 at 16:15
  • \$\begingroup\$Suggestion? Good point also.\$\endgroup\$CommentedAug 2, 2020 at 16:16

2 Answers2

7
\$\begingroup\$

Use Common Definitions Rather Than Hard Coded Values

I agree with @pm100 aboutNULL, it is much more common to useNULL rather than 0x00. Very early C++ compilers also usedNULL rather thannullptr.

Sincestdlib.h is already included, the exit constantsEXIT_SUCCESS andEXIT_FAILURE are availble, this would make the code more readable and maintainable.

Most modern C and C++ compilers will add a finalreturn 0; to the code so the return inmain() isn't strictly necessary.

Prefersize_t When the Variable Can Be Used As an Index

In main the variablei should be declared assize_t rather thanint. If you compile -Wall you will find that the comparison betweeni andself_readBuff->size yields a type mismatch warning betweenint andsize_t.

In the declaration ofN##t_getat(unsigned int idx, N##_t* _this) theunsigned int should also besize_t.

Prefer Local Variables Over Global Variables

I would suggest a separate macro to define the variable of the proper type so that it can be used in a function rather than having a global variable.

Inmain() it would be better ifself_readBuff was declared locally rather than as a static variable globally. The variable ``self_##N` is not used anywhere else globally.

Only Code What is Necessary

The header filestring.h is not necessary and slows down compile time. The variables inmain() is never referenced.int s = self_readBuff->size;

Keep it Simple

I would have defined each function as a separate macro and then included all of them in a single macro for ease of debugging and possible separate use. It will also make the code easier to maintain if each function can be maintained separately.

answeredAug 1, 2020 at 21:03
pacmaninbw's user avatar
\$\endgroup\$
4
  • 1
    \$\begingroup\$Note that using a signed type instead ofsize_t will allow the compiler to optimize more aggressively, but it may also leads bugs. If you use an unsigned type for array/pointer indices, always usesize_t. Also, don't optimize prematurely.\$\endgroup\$CommentedAug 2, 2020 at 12:57
  • 1
    \$\begingroup\$Don't you mean "Onlyinclude what is necessary"?\$\endgroup\$CommentedAug 2, 2020 at 15:25
  • \$\begingroup\$@einpoklum Mostly, but that would leave out the referenced variables.\$\endgroup\$CommentedAug 2, 2020 at 15:30
  • 1
    \$\begingroup\$Good suggestions. Also I am thinking how convinient would be to make a dynamic array of that dynamic array, guess I will play a bit more taking note of your suggestions.\$\endgroup\$CommentedAug 2, 2020 at 17:04
3
\$\begingroup\$

my 2 cents worth

v nice clean code.

I would have called the generated variable N not self_N. That looks peculiar , plus all the other generated names are N## something, having something##N is also odd. In the macro call I said I wanted it called 'readBuff' so call it that.

the use of 0x00 for null is certainly correct buts its the first time I have ever seen it, its not idiomatic. I would say NULL (or plain 0).

Did you consider the possibility of creating the struct on the stack or statically? I mean there is no reason to place it on the heap. It doesn't grow and you don't need variable numbers of them.

answeredAug 1, 2020 at 18:50
pm100's user avatar
\$\endgroup\$
1
  • \$\begingroup\$Thank you. Will consider it. Feel free to add a snippet\$\endgroup\$CommentedAug 1, 2020 at 19:35

You mustlog in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.