Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Two types in the same dynamic allocation

The ISO C90 Standard (or at least the draft of it that I have) says this about malloc and alignment:

The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object and then used to access such an object or an array of such objects in the space allocated...

But can you use the same pointer returned by malloc for two different types? For example, suppose that I know that sizeof(int) <= 2 * sizeof(short). Could I allocate enough memory for 5 shorts, and use the first two as an int, i.e. is the following code guaranteed to work as intended?

#include <stdio.h>
#include <stdlib.h>
int main(void) {
    void* data = malloc(5 * sizeof(short));
    short* short_array = data;
    int* int_ptr = data;
    if (!data) return EXIT_FAILURE;
    *int_ptr = 13943;
    short_array += 2; /* Skip over the int */
    short_array[0] = 7;
    short_array[1] = 238;
    short_array[2] = -123;
    printf("%d %d %d %d\n", *int_ptr, short_array[0], short_array[1], short_array[2]);
    free(data);
    return 0;
}

I've tried this code, and it does output 13943 7 238 -123 for me, but I'm not entirely sure if it's standard-compliant.


Edit: Specifically, I'm trying to make a dynamic array type (which can be an array of any type), so I'm allocating an array of one type, and using the start of that allocation as a pointer to a header which contains the length and capacity of the array.

To be clear, here is approximately what I'm doing:

size_t header_elements = (sizeof(ArrayHeader) + array_type_size - 1) / array_type_size); /* = ceil(sizeof(ArrayHeader) / array_type_size) */
void* data = malloc((header_elements + array_length) * array_type_size);
ArrayHeader* header = data;
void* array = (char*)data + header_elements * array_type_size;

So, header points to the start of the allocation and the actual array is offset by a multiple of the size of the type stored in it.

like image 898
pommicket Avatar asked Jan 27 '26 22:01

pommicket


1 Answers

C90 ought to be dead by now, rest in peace. The C99, C11 and C18 behaviour is the one that should be considered here. They talk a lot about effective types. As the object allocated by malloc is not typed as such, the compiler will track the types of each pointer and memory area.

If you write an int to the first 4 bytes, then the compiler is allowed to consider the datatype at the first 4 bytes to be an int. If then you write shorts to the successive bytes, their effective type will be short. If the storage does not overlap then your code is OK.

But - be careful: if you however overlap the storage, i.e. you'll write the short over the int and read back the int afterwards, then all bets are off.

Finally there is a rather good way of avoiding ambiguity - use a struct type. How about just using

struct two_types_in_one_malloc {
    int the_int;
    short the_shorts[3];
};
like image 198


Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!