Create data type of n size bytes

廉价感情. 提交于 2021-01-29 10:03:11

问题


I am making a stretchy-buffer-like single-file header library for queues in C.
I am passing the array as a void* and the size of a single element to one of the functions:

void func(void* arr, size_t itemsize);

Inside func() I need to do some pointer arithmetic with arr.
I can't do arithmetic with void*, so I thought I could create a data type of size itemsize that I could cast arr into, and thus solve my problem.

I saw the accepted this question, but would pointer arithmetic on char*[] work the way I want? As in, (char*[5])(arr) + 3 is 15 bytes past arr, and &((char*[4])(arr))[6] points to 24 bytes past arr.

I need to create the type inside func.


回答1:


We can look at how GLib does their arrays. And if this is for production code, just use GLib.

First, don't pass around the size and pointer. Make a struct which contains the size and the array and anything else. This allows you to pass around the complete array. Far simpler and less error prone. Here's how how GLib does it. The important bits are data (guint8 is the GLib version of uint8 or 1 byte) and elt_size (element size). The rest is gravy.

struct _GRealArray
{
  guint8 *data;
  guint   len;
  guint   alloc;
  guint   elt_size;
  guint   zero_terminated : 1;
  guint   clear : 1;
  gatomicrefcount ref_count;
  GDestroyNotify clear_func;
};

We can look at g_array_insert_vals to see how to insert values at an index. The meat of the insertion is here.

memcpy (g_array_elt_pos (array, index_), data, g_array_elt_len (array, len));

The special sauce is all in the g_array_elt_pos (element position) and g_array_elt_len (element size) macros. g_array_elt_pos(array, i) replicates array[i].

#define g_array_elt_len(array,i) ((array)->elt_size * (i))
#define g_array_elt_pos(array,i) ((array)->data + g_array_elt_len((array),(i)))

The data is stored as 8 bit integers. g_array_elt_len calculates the offset from the start of the array by multiplying the element size by the index. Then g_array_elt_pos adds that to the start of the array.

That memcpy is effectively...

memcpy(array[index_], data, (array->elt_size * len));

Copy len units of array->elt_size size from data to array[i].


Looking up an element requires a type cast. GLib takes care of this for you with a macro. It returns a pointer to the element.

#define g_array_index(a,t,i)      (((t*) (void *) (a)->data) [(i)])

For example.

// Similar to double num = array[5]
// Expands to ((double*) (void *) array->data)[5]
double num = g_array_index(array, double, 5);



回答2:


I am confused by the last sentence of your question: however 20 not 15, 28 not 24. Ie base address + three scalars = fourth element of base zero array. Suggest define and declaring your array as a block of unsigned char rather than void. Next use union {} instead of type casting and pointer arithmetic. Alignment may be another issue. So instead of passing a base pointer and an element size, simply pass the base pointer and the byte size of the varying array, implying an implied element size and type. Or explicitly pass all three.



来源:https://stackoverflow.com/questions/63333480/create-data-type-of-n-size-bytes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!