将void *指针强制转换为char *指针并在其上执行指针算术是一种有效的操作吗?

时间:2017-12-29 21:24:32

标签: c arrays list pointers

我在内存中有一个malloc< ed *块/数组的指针(void *),我知道存储在该块中的数据结构的大小。我希望能够遍历块以访问任何单个值。

程序知道:

  • void *指针将指向此malloc内存块的开头。

  • 每个值的大小[以字节为单位],但不是实际存储的数据结构。

  • 容量[以字节为单位]:这些值的潜在数量(分配了多少内存)

这意味着我有malloc' ed:Capacity * Size_of_value字节,我希望通过以下方式获取指向该块内任何值的指针:

  1. 将void *指针转换为char *指针。

  2. 将所需的Size_of_value倍数添加到char *指针:从而获得指向任何所需值的指针。

  3. 我学到的是将N添加到char *指针,使其向前移动N个字节。而且我知道指针必须以[amount]字节向前移动,我可以将[amount]添加到此char *指针。

    我无法找到合适的来源,并且通常只能确定无法使用虚拟化合物*。

    从我到目前为止的黑客攻击,它似乎正常工作,只要存储的结构具有恒定的已知大小。结构中的灵活数组成员会破坏我当前的实现。这是我计划通过创建扩展来修复的缺点:列表将保存指向指针数组的指针,这些指针将允许访问实际值。

    可能有用或可能没用的上下文:

    我正在开发一个列表数据结构的实现,我实现它基本上是一个动态数组(在需要时扩展和收缩)和更多接口。

    我知道链接列表,我也计划将它们作为一种不同的练习来实现。

    我定义了这样的列表:

    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.
    

    获取指向给定索引值的指针的函数:

    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;
    }
    

    我发现的其他信息:

    GNU C编译器提供了一种C语言扩展,允许对void*进行算术运算,将其视为大小为1(就像它被转换为char*一样):

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

    ISO C中不允许这样做,仅在GNU C中。

2 个答案:

答案 0 :(得分:4)

是的,转换为char *始终是合法的,取消引用该指针仅在分配的块的范围内是合法的。

答案 1 :(得分:1)

C99标准在6.3.2.3中说:

  

指向void的指针可以转换为指向any的指针   不完整或对象类型。指向任何不完整或对象类型的指针   可以转换为指向void的指针,然后再返回;结果应该   比较等于原始指针。

所以,只要你使用实际类型的指针(在本例中为char *)进行算术运算,它就完全有效。