cuser-defined-data-types

An array of data types in C?


I have two data types with different-sized fields of the same name. I am trying to access these fields based on a parameter I pass in to a function--- say

struct smallindex
{
   unsigned char index;
   unsigned int count;
};
struct largeindex
{
   unsigned int index;
   unsigned long count;
};

This is possibly not an ideal thing to do-- but one way to implement this is, to have the function treat a pointer as a pointer of different sizes. Say, something like:

void function(int index, void *ptr)
{
   array[] = {struct smallindex, struct largeindex};
   array[index] *pointer = *ptr;
   *pointer[1].index++;
   return;
}

However, the compiler does not like this at all. I tried several other implementations-- but none of them worked. The variability in the bit field size prevented me from trying a union. Is this doable?

Alternatively, if I pad the index sizes to make sure their size matches (but their positions of fields will still not match)-- is this doable then?


Solution

  • Inside the function, you can convert ptr to type char * or int *, or to a pointer to a struct or union type, but every pointer points to exactly one type. Such a conversion produces undefined behavior if the result would fail to be appropriately aligned for the pointer type, but that will not happen when casting to a type of object that ptr actually does point to.

    Furthermore, you can freely access the bytes of any object's representation via a pointer of character type (char *, unsigned char *, etc.). If you attempt to access an object via a pointer to an object of a different, incompatible type, however, then you produce undefined behavior. Accessing the pointed-to object is a separate consideration from converting the pointer to a different pointer type.

    Thus, you can do this:

    void function(int index, void *ptr) {
        // treat `ptr` as pointing to the first element of an array of int
        int *pointer = ptr;
        pointer[index]++;  // UB here if ptr really points to something other than int
    }
    

    and this:

    void function(int index, void *ptr) {
        // treat `ptr` as pointing to the first element of an array of char
        char *pointer = ptr;
        pointer[index]++;
    }
    

    and even this:

    void function(int index, void *ptr, _Bool is_int_ptr) {
        // Treat ptr as pointing to char or int depending on the value of is_int_ptr
        if (is_int_ptr) {
            int *pointer = ptr;
            pointer[index]++;
        } else {
            char *pointer = ptr;
            pointer[index]++;
        }
    }
    

    But the pointer value itself does not carry information about which type it points to. You need a mechanism to tell the program which type it points to. Ordinarily, that would be via the function parameter's declared type (making the function specific to that type), but you can convey it via a separate parameter, as in the last example.