tehftw
tehftw

Reputation: 149

Is it a valid operation to cast a void* pointer to char* pointer and doing pointer arithmetics on it?

I have a Pointer(void*) to a malloc'ed block/array in memory, and I know the Size of the data structure that is stored in that block. I want to be able to iterate over the block to get access to any single value.

Program knows:

This means that I have malloc'ed: Capacity*Size_of_value bytes, and I want to get a pointer to any value that is inside that block, by:

  1. Casting the void* Pointer into char* Pointer.

  2. Adding a required multiple of Size_of_value to the char*Pointer: thus getting a pointer to any required value.

What I learned, is that adding N to a char* pointer, causes it to move forward by N bytes. And as I know that the pointer has to be moved forward by [amount] of bytes, I can add [amount] to this char* pointer.

I couldn't find a proper source for this, and generally only found out for sure that arithmetics on a void* isn't allowed.

From what I hacked together so far, it seems to work properly, as long as the stored structure has a constant, known size. A flexible array member in the struct breaks my current implementation. This is a shortcoming that I'm planning to fix by creating an extension: the list will hold a pointer to an array of pointers, and those pointers will give access to the actual values.


Context that might or might not be useful:

I am working on an implementation of a list data structure, and I implemented it as basically a dynamic array(expanding and shrinking whenever needed) with more interface.

I know about linked lists, and I'm also planning to implement them as a different exercise.

I defined the list like this:

typedef struct TLIST_
{
    size_t size_of_value;      // size [in bytes] of each record stored in the list
    size_t list_capacity;      // memory has been allocated for this many values(size can't be larger than this)

    size_t list_size;          // number of stored records 
    void* pointer_to_zero;     // address of the content
} tlist;

// The list has a few other values for various options and operations(e.g.: disallowing it to expand automatically, displaying the content), but those four values is all that's needed for this problem.

The function for getting a pointer to a value at given index:

void* tehlist_generic_getPointerToIndex(const tlist* list__, const int index__) 
{
    const int capacity =  (*list__).list_capacity;
    if( index__ >= 0 && index__ < capacity )
    {
        // Move pointer forward by a given amount of bytes, through casting the void* to a char*
        // 1. Can't do pointer arithmetic on void*, but can on char*
        // 2. char* is defined as 1[unit or byte],
        // thus moving char* forward by N, causes it to move as if we were moving through a pointer that was of size N

        void* pointer_to_index = (*list__).pointer_to_zero;

        const size_t bytes_forward = (*list__).size_of_value*index__;
        pointer_to_index = (char*)(pointer_to_index) + ( bytes_forward );

        return pointer_to_index;
    }
    return 0;
}

Additional information I found:

GNU C compiler offers a C language extensions that allows arithmetic on void*, by treating it as if it had size of 1 (like it was casted into char*):

https://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html#Pointer-Arith

This isn't allowed in ISO C, only in GNU C.

Upvotes: 4

Views: 683

Answers (2)

mdatsev
mdatsev

Reputation: 3879

The C99 standard says in 6.3.2.3:

A pointer to void may be converted to or from a pointer to any incomplete or object type. A pointer to any incomplete or object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.

So yes it is perfectly valid as long as you do the arithmetic with the pointer of the actual type(in this case char*).

Upvotes: 1

SoronelHaetir
SoronelHaetir

Reputation: 15172

Yes, casting to char * is always legal, dereferencing that pointer is only legal within the bounds of the allocated block.

Upvotes: 4

Related Questions