Using max_align_t to store a chunk of bytes - c

In this thread I was suggested to use max_align_t in order to get an address properly aligned for any type, I end up creating this implementation of a dynamic array:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
struct vector {
size_t capacity;
size_t typesize;
size_t size;
max_align_t data[];
};
#define VECTOR(v) ((struct vector *)((unsigned char *)v - offsetof(struct vector, data)))
static void *valloc(size_t typesize, size_t size)
{
struct vector *vector;
vector = calloc(1, sizeof(*vector) + typesize * size);
if (vector == NULL) {
return NULL;
}
vector->typesize = typesize;
vector->capacity = size;
vector->size = 0;
return vector->data;
}
static void vfree(void *data, void (*func)(void *))
{
struct vector *vector = VECTOR(data);
if (func != NULL) {
for (size_t iter = 0; iter < vector->size; iter++) {
func((unsigned char *)vector->data + vector->typesize * iter);
}
}
free(vector);
}
static void *vadd(void *data)
{
struct vector *vector = VECTOR(data);
struct vector *new;
size_t capacity;
if (vector->size >= vector->capacity) {
capacity = vector->capacity * 2;
new = realloc(vector, sizeof(*vector) + vector->typesize * capacity);
if (new == NULL) {
return NULL;
}
new->capacity = capacity;
new->size++;
return new->data;
}
vector->size++;
return vector->data;
}
static size_t vsize(void *data)
{
return VECTOR(data)->size;
}
static void vsort(void *data, int (*comp)(const void *, const void *))
{
struct vector *vector = VECTOR(data);
if (vector->size > 1) {
qsort(vector->data, vector->size, vector->typesize, comp);
}
}
static char *vgetline(FILE *file)
{
char *data = valloc(sizeof(char), 32);
size_t i = 0;
int c;
while (((c = fgetc(file)) != '\n') && (c != EOF)) {
data = vadd(data);
data[i++] = (char)c;
}
data = vadd(data);
data[i] = '\0';
return data;
}
struct data {
int key;
char *value;
};
static int comp_data(const void *pa, const void *pb)
{
const struct data *a = pa;
const struct data *b = pb;
return strcmp(a->value, b->value);
}
static void free_data(void *ptr)
{
struct data *data = ptr;
vfree(data->value, NULL);
}
int main(void)
{
struct data *data;
data = valloc(sizeof(struct data), 1);
if (data == NULL) {
perror("valloc");
exit(EXIT_FAILURE);
}
for (size_t i = 0; i < 5; i++) {
data = vadd(data);
if (data == NULL) {
perror("vadd");
exit(EXIT_FAILURE);
}
data[i].value = vgetline(stdin);
data[i].key = (int)vsize(data[i].value);
}
vsort(data, comp_data);
for (size_t i = 0; i < vsize(data); i++) {
printf("%d %s\n", data[i].key, data[i].value);
}
vfree(data, free_data);
return 0;
}
But I'm not sure if I can use max_align_t to store a chunk of bytes:
struct vector {
size_t capacity;
size_t typesize;
size_t size;
max_align_t data[]; // Used to store any array,
// for example an array of 127 chars
};
Does it break the one past the last element of an array rule?

Does it break the one past the last element of an array rule?
No.
Using max_align_t to store a chunk of bytes
OP's issue is not special because it uses a flexible array member.
As a special case, the last element of a structure ... have an incomplete array type; this is called a flexible array member. ... However, when a . (or ->) operator has a left operand that is (a pointer to) a structure with a flexible array member and the right operand names that member, it behaves as if that member were replaced with the longest array (with the same element type) ...
It is the same issue as accessing any allocated memory or array of one type as if it was another type.
The conversion from max_align_t * to char * to void * is well defined when alignment is done right.
A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined. C11dr ยง6.3.2.3 7
All reviewed accessing in code do not attempt to access outside the "as if" array.

Related

Is there a way to dereference a void pointer in C?

The calloc function in C returns a void pointer but the memory bytes pointed to are already initialized with values, How is this is achieved?
I am trying to write a custom calloc function in C but can't find a way to initialize the allocated memory bytes
My code
#include "main.h"
/**
* _calloc - Allocate memory for an array
* #nmemb: Number of elements
* #size: Size of each element
*
* Description: Initialize the memory bytes to 0.
*
* Return: a Void pointer to the allocated memory, if error return NULL
*/
void *_calloc(unsigned int nmemb, unsigned int size)
{
unsigned int i, nb;
void *ptr;
if (nmemb == 0 || size == 0)
return NULL;
nb = nmemb * size;
ptr = malloc(nb);
if (ptr == NULL)
return NULL;
i = 0;
while (nb--)
{
/*How do i initialize the memory bytes?*/
*(ptr + i) = '';
i++;
}
return (ptr);
}
Simply use pointer to another type to dereference it.
example:
void *mycalloc(const size_t size, const unsigned char val)
{
unsigned char *ptr = malloc(size);
if(ptr)
for(size_t index = 0; index < size; index++) ptr[index] = val;
return ptr;
}
or your version:
//use the correct type for sizes and indexes (size_t)
//try to have only one return point from the function
//do not use '_' as a first character of the identifier
void *mycalloc(const size_t nmemb, const size_t size)
{
size_t i, nb;
char *ptr = NULL;
if (nmemb && size)
{
nb = nmemb * size;
ptr = malloc(nb);
if(ptr)
{
i = 0;
while (nb--)
{
//*(ptr + i) = 'z';
ptr[i] = 'z'; // isn't it looking better that the pointer version?
i++;
}
}
}
return ptr;
}
Then you can use it assigning to other pointer type or casting.
example:
void printByteAtIndex(const void *ptr, size_t index)
{
const unsigned char *ucptr = ptr;
printf("%hhu\n", ucptr[index]);
}
void printByteAtIndex1(const void *ptr, size_t index)
{
printf("%hhu\n", ((const unsigned char *)ptr)[index]);
}

Are multiple variable-length arrays in a structure in C possible?

Is something like this possible in C? It would be really nice to have both of these.
typedef struct {
int r;
char a0[0];
char a1[0];
}
No. Rather use dynamically allocated memory. Something like:
typedef struct {
int *data1;
size_t len1
int *data;
size_t len2;
} sometype;
sometype *alloc_sometype(size_t len1, size_t len2) {
sometype *n = malloc(sizeof(sometype));
if (!n) return NULL;
n->len1 = len1;
n->len2 = len2;
n->data1 = malloc(sizeof(int) * len1);
n->data2 = malloc(sizeof(int) * len2);
// Error handling if those malloc calls fail
return n;
}
The flexible array must be the last member in the struct so you can't have two. However, if both arrays are supposed to have the same size, you could combine them:
#include <stdio.h>
#include <stdlib.h>
typedef struct { // a struct to keep one a0 a1 pair
char a0;
char a1;
} A;
typedef struct {
size_t len;
A a[]; // flexible array of a0 a1 pairs
} data;
data *data_create(size_t len) {
data *d = malloc(sizeof *d + len * sizeof *d->a);
if(d) d->len = len;
return d;
}
int main() {
data *d = data_create(10);
for(size_t i = 0; i < d->len; ++i) {
d->a[i].a0 = i;
d->a[i].a1 = i+1;
}
free(d);
}

Assign variable void* to array of void C

So I have an array, without any specified type:
void* buff = malloc(size*eltSize);
And I have a function, that has a void* parameter, and I want to assign it to the array, something like this:
void function(void* p1){
buff[i] = p1;
}
I know that this doesn't work, but say I want to make it as generic as possible, what's the best way to do? Remember, I have no idea about the types used (It should accept any type possible; even struct).
Thank you
You have to pass the element size (and the array index, for that matter) manually each time, similar to how qsort works. You'd have to change your function to something like:
void function(void * buff, void * p1, size_t elt_size, size_t index){
memcpy(((char *) buff) + index * elt_size, p1, elt_size);
}
and call it such as:
int array[] = {3, 1, 4, 1, 5, 9};
int n = 8;
function(array, &n, sizeof(n), 5); // Equivalent to array[5] = n;
A full working example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void function(void * buf, void * data, size_t elt_size, size_t index)
{
memcpy(((char *) buf) + index * elt_size, data, elt_size);
}
int main(void)
{
int narray[] = {3, 1, 4, 1, 5, 9};
int n = 8;
function(narray, &n, sizeof(n), 5); // Equivalent to array[5] = n
for ( size_t i = 0; i < sizeof(narray) / sizeof(narray[0]); ++i ) {
printf("Value of element [%zu] is: %d\n", i, narray[i]);
}
char * sarray[] = {"The", "mome", "raths", "outgrabe"};
char * p = "barked";
function(sarray, &p, sizeof(p), 3); // Equivalent to sarray[3] = p
for ( size_t i = 0; i < sizeof(sarray) / sizeof(sarray[0]); ++i ) {
printf("Value of element [%zu] is: %s\n", i, sarray[i]);
}
return 0;
}
with output:
Paul#Pauls-iMac:~/Documents/src/sandbox$ ./generic2
Value of element [0] is: 3
Value of element [1] is: 1
Value of element [2] is: 4
Value of element [3] is: 1
Value of element [4] is: 5
Value of element [5] is: 8
Value of element [0] is: The
Value of element [1] is: mome
Value of element [2] is: raths
Value of element [3] is: barked
Paul#Pauls-iMac:~/Documents/src/sandbox$
Obviously it will work just as well with arrays dynamically allocated with malloc() as it will with the regular arrays that this example uses.
You can eliminate the need to pass the element size every time if you create a struct to hold the data and the element size together, for instance:
struct generic_array {
void * data;
size_t elt_size;
}
When you pass a pointer to this struct to your function, it'll be able to access the element size itself, both eliminating the need for you to provide it, and eliminating a whole category of bugs arising from you inadvertently passing the wrong size. If you add a third member to store the number of elements you initially malloc()ed, then you can do bounds-checking, too.
Full working example of that approach:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct generic_array {
void * data;
size_t elt_size;
size_t size;
};
struct generic_array * generic_array_create(const size_t elt_size,
const size_t size)
{
struct generic_array * new_array = malloc(sizeof *new_array);
if ( !new_array ) {
perror("couldn't allocate memory for array");
exit(EXIT_FAILURE);
}
void * data = malloc(size * elt_size);
if ( !data ) {
perror("couldn't allocate memory for array data");
exit(EXIT_FAILURE);
}
new_array->data = data;
new_array->elt_size = elt_size;
new_array->size = size;
return new_array;
}
void generic_array_destroy(struct generic_array * array)
{
free(array->data);
free(array);
}
void generic_array_set(struct generic_array * array, void * elem,
const size_t index)
{
if ( index >= array->size ) {
fprintf(stderr, "Index %zu out of bounds of size %zu.\n",
index, array->size);
exit(EXIT_FAILURE);
}
memcpy(((char *)array->data) + index * array->elt_size,
elem, array->elt_size);
}
void generic_array_get(struct generic_array * array, void * elem,
const size_t index)
{
if ( index >= array->size ) {
fprintf(stderr, "Index %zu out of bounds of size %zu.\n",
index, array->size);
exit(EXIT_FAILURE);
}
memcpy(elem, ((char *)array->data) + index * array->elt_size,
array->elt_size);
}
int main(void)
{
int narray[] = {3, 1, 4, 1, 5, 9};
const size_t nsize = sizeof(narray) / sizeof(narray[0]);
struct generic_array * garray = generic_array_create(sizeof(int), nsize);
for ( size_t i = 0; i < nsize; ++i ) {
generic_array_set(garray, &narray[i], i);
}
for ( size_t i = 0; i < nsize; ++i ) {
int n;
generic_array_get(garray, &n, i);
printf("Value of element %zu: %d\n", i, n);
}
generic_array_destroy(garray);
return 0;
}
If you want to copy an object, and you don't know its type, only its size, you use memcpy:
void* buff = malloc(size*eltSize);
void function(void* p1) {
memcpy((char *)buff + i * eltSize, p1, eltSize);
}
Since you don't know the type, you can't use indexing directly, but rather have to manually calculate the address with pointer arithmetic.
Since you try to insert pointer to void type as element to buff, then buff must be of void** type.
int i = 0;
void* *buff = malloc(size * sizeof(void*));
if (buff == NULL)
// handle error
void function(void* p1) {
buff[i] = p1; // now OK
}
This is a potential solution if you want to remember the corresponding type of each data stored in your generic array. I used a fixed size array, and add basic type in the enum and just two exemple of how to get back your data in their respective type.
You could use function pointers if you have more type and don't want to use a lot the 'if' statements.
#include <stdio.h>
enum type {
INT,
FLOAT,
CHAR,
STRING
};
struct gen_array {
enum type elm_type;
void *data;
};
int to_int(void *data) {
return ((int) data);
}
char *to_string(void *data) {
return ((char *) data);
}
void printer(struct gen_array *arr, size_t size) {
for (size_t i = 0; i < size; i++) {
if (arr[i].elm_type == STRING)
printf("%s\n", to_string(arr[i].data));
if (arr[i].elm_type == INT)
printf("%d\n", to_int(arr[i].data));
}
}
int main(void) {
struct gen_array buff[2];
struct gen_array elm_0;
elm_0.elm_type = INT;
elm_0.data = (void*)10;
buff[0] = elm_0;
struct gen_array elm_1;
elm_1.elm_type = STRING;
elm_1.data = (void*)"helloWorld!";
buff[1] = elm_1;
printer(buff, 2);
return (0);
}

C : Insert/get element in/from void array

I have to create a generic array that can contain generic data structures.
How can i put a generic structure into an empty slot of my void array?
This is my code.
struct CircularBuffer {
int E;
int S;
int length; // total number of item allowable in the buffer
int sizeOfType; // size of each element in the buffer
void *buffer;
};
struct CircularBuffer* circularBufferInit(int length, int sizeOfType) {
struct CircularBuffer *cb = malloc(sizeof(struct CircularBuffer));
cb->E = 0;
cb->S = 0;
cb->length = length;
cb->sizeOfType = sizeOfType;
cb->buffer = malloc(sizeOfType *length);
return cb;
}
int circularBufferIsEmpty(struct CircularBuffer* cb) {
if (cb->S == cb->E)
return 1; //empty
else
return 0;
}
int circularBufferIsFull(struct CircularBuffer *cb) {
int nE = (cb->E + 1) % (cb->length);
if (nE == cb->S)
return 1; //full
else
return 0;
}
void circularBufferAdd(struct CircularBuffer *cb, void* obj) {
memcpy(cb->buffer + cb->E, obj, cb->sizeOfType);
}
[...]
memcpy is the problem...
It seems that essentially you're trying to figure out how to offset a void * to the address of an array element of known size but unknown type so you can pass it to memcpy().
It looks as though, in circularBufferAdd(), cb->E gives the index of the element you want to copy to, cb->buffer is the void * to the array, obj is the item to be copied, and cb->sizeOfType is the size each array element (and obj). In that case you can change:
memcpy(cb->buffer + cb->E, obj, cb->sizeOfType);
to:
memcpy((char *)cb->buffer + (cb->E * cb->sizeOfType), obj, cb->sizeOfType);
Since you can't use pointer arithmetic with a void *, you'd cast it to char *. Then, you can multiply the element index by the element size to get the offset of the element in bytes, and use that to get the address of the element you need.

Creating a Generic Circular Buffer

Given the desire to abstract the structure of a circular buffer from its content, and starting from the following code segments (courtesy of this wikipedia entry):
typedef struct
{
int value;
} ElemType;
typedef struct
{
int size; /* total number of elements */
int start; /* index of oldest element */
int count; /* index at which to write new element */
ElemType *elements; /* vector of elements */
} CircularBuffer;
void cbInit(CircularBuffer *cb, int size) {
cb->size = size;
cb->start = 0;
cb->count = 0;
cb->elements = (ElemType *)calloc(cb->size, sizeof(ElemType));
}
How does one abstract the element type so that it is specified when an instance of the CircularBuffer is defined? My attempt thus far is as follows:
CircularBuffer *cbInit(uint16 size, void *element)
{
CircularBuffer *buffer;
buffer = malloc(sizeof(*buffer));
if (buffer != NULL)
{
buffer->size = size;
buffer->start = 0;
buffer->count = 0;
buffer->elements = (void *)calloc(size, sizeof(???));
if (buffer->elements == NULL)
{
free(buffer);
buffer = NULL;
}
}
return buffer;
}
But I cannot figure out how to determine the size of an unknown type, which may be an int, a struct, or anything in between. Is what I am attempting to do even possible?
As you've found out, you can't automatically tell the size of an unknown piece of data. You'll need either a fixed element type (void* would be a good generic choice), or have the user pass in the size of each element:
CircularBuffer *cbInit(uint16 size, int elementSize)
{
...
buffer->elementSize = elementSize;
buffer->elements = calloc(size, elementSize);
}

Resources