Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a char array be used with any data type?

Tags:

arrays

c

types

c11

The malloc() function returns a pointer of type void*. It allocates memory in bytes according to the size_t value passed as argument to it. The resulting allocation is raw bytes which can be used with any data type in C(without casting).

Can an array with type char declared within a function that returns void *, be used with any data type like the resulting allocation of malloc?

For example,

#include <stdio.h>

void *Stat_Mem();

int main(void)
{
    //size : 10 * sizeof(int)
    int buf[] = { 1,2,3,4,5,6,7,8,9,10 };

    int *p = Stat_Mem();

    memcpy(p, buf, sizeof(buf));

    for (int n = 0; n < 10; n++) {
        printf("%d ", p[n]);
    }
    putchar('\n');

    return 0;
}

void *Stat_Mem()
{
    static char Array[128];
    return Array;
}
like image 358
machine_1 Avatar asked Jul 21 '16 17:07

machine_1


2 Answers

The declared type of the static object Array is char. The effective type of this object is it's declared type. The effective type of a static object cannot be changed, thus for the remainder of the program the effective type of Array is char.

If you try to access the value of an object with a type that is not compatible with, or not on this list1, the behavior is undefined.

Your code tries to access the stored value of Array using the type int. This type is not compatible with the type char and is not on the list of exceptions, so the behavior is undefined when you read the array using the int pointer p:

printf("%d ", p[n]);

1 (Quoted from: ISO:IEC 9899:201X 6.5 Expressions 7 )
An object shall have its stored value accessed only by an lvalue expression that has one of the following types:
— a type compatible with the effective type of the object,
— a qualified version of a type compatible with the effective type of the object,
— a type that is the signed or unsigned type corresponding to the effective type of the object,
— a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
— an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
— a character type.

like image 162
2501 Avatar answered Nov 04 '22 21:11

2501


No you cannot use an arbitrary byte array for an arbitrary type because of possible alignment problems. The standard says in 6.3.2.3 Conversions/Pointers (emphasize mine):

A pointer to an object or incomplete type may be converted to a pointer to a different object or incomplete type. If the resulting pointer is not correctly aligned for the pointed-to type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to the original pointer.

As a char as the smallest alignment requirement, you cannot make sure that your char array will be correctly aligned for any other type. That is why malloc guarantees that a buffer obtained by malloc (even if it is a void *) has the largest possible alignement requirement to be able to accept any other type.


I think that

union {
    char buf[128];
    long long i;
    void * p;
    long double f;
};

should have correct alignment for any type as it is compatible with largest basic types (as defined in 6.2.5 Types). I am pretty sure that it will work for all common implementations (gcc, clang, msvc, ...) but unfortunately I could not find any confirmation that the standard allows it. Essentially because of the strict aliasing rule as defined in 6.5 Expression §7:

An object shall have its stored value accessed only by an lvalue expression that has one of the following types:

  • a type compatible with the effective type of the object,
  • a qualified version of a type compatible with the effective type of the object,
  • a type that is the signed or unsigned type corresponding to the effective type of the object,
  • a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
  • an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
  • a character type.

So IMHO there is not portable and standard conformant way to build a custom allocator not using malloc.

like image 28
Serge Ballesta Avatar answered Nov 04 '22 21:11

Serge Ballesta