用于使用字节偏移进行操作的更清晰的指针算术语法

时间:2009-10-26 04:04:29

标签: c++ c pointers char pointer-arithmetic

在以下代码行中,我需要将指针pm调整为其字段之一的字节偏移量。是否有更好/更简单的方法来执行此操作,而不是从char *PartitionMap *不断地来回转换,以便指针算法仍然有效?

PartitionMap *pm(reinterpret_cast<PartitionMap *>(partitionMaps));
for ( ; index > 0 ; --index)
{
    pm = (PartitionMap *)(((char *)pm) + pm->partitionMapLength);
}
return pm;

对于那些无法从代码中删除的人,它会在从PartitionMap继承的缓冲区中循环遍历可变长度描述符。

对于那些有关的人,partitionMapLength总是返回运行它的系统支持的长度。我正在遍历的数据符合UDF规范。

7 个答案:

答案 0 :(得分:5)

Casting是唯一的方法,无论是char *或intptr_t还是其他类型的,然后是你的最终类型。

答案 1 :(得分:5)

我经常使用这些模板:

    template<typename T>
    T *add_pointer(T *p, unsigned int n) {
            return reinterpret_cast<T *>(reinterpret_cast<char *>(p) + n);
    }

    template<typename T>
    const T *add_pointer(const T *p, unsigned int n) {
            return reinterpret_cast<const T *>(reinterpret_cast<const char *>(p) + n);
    }

它们维护类型,但为它们添加单个字节,例如:

T *x = add_pointer(x, 1); // increments x by one byte, regardless of the type of x

答案 2 :(得分:3)

你当然可以保留两个变量:一个char *来逐步通过缓冲区,一个PartitionMap *来访问它。让事情变得更加清晰。

for (char *ptr = ??, pm = (PartitionMap *)ptr ; index > 0 ; --index)
{
    ptr += pm->partitionMapLength;
    pm = (PartitionMap *)ptr;
}
return pm;

答案 3 :(得分:1)

正如其他人所说,你需要演员,但你可以隐藏宏观或功能中的丑陋。但是,要记住的另一件事是对齐要求。在大多数处理器上,您不能简单地将指针增加到任意数量的字节,并将结果转换回指向原始类型的指针,而不会因为未对齐而通过新指针访问结构。

x86架构中,为数不多的架构之一(即使它是最受欢迎的架构)也能让您轻松获得它。但是,即使您正在为Windows编写,也需要考虑此问题 - Win64确实强制执行对齐要求。

因此,即使通过指针访问partitionMapLength成员,也可能导致程序崩溃。

您可以在Windows上使用__unaligned之类的编译器扩展轻松解决此问题:

PartitionMap __unaliged *pm(reinterpret_cast<PartitionMap *>(partitionMaps));
for ( ; index > 0 ; --index)
{
    pm = (PartitionMap __unaligned *)(((char *)pm) + pm->partitionMapLength);
}
return pm;

或者您可以将可能未对齐的数据复制到正确对齐的结构中:

PartitionMap *pm(reinterpret_cast<PartitionMap *>(partitionMaps));

char* p = reinterpret_cast<char*>( pm);

ParititionMap tmpMap;
for ( ; index > 0 ; --index)
{

    p += pm->partitionMapLength;

    memcpy( &tmpMap, p, sizeof( newMap));
    pm = &tmpMap;
}

// you may need a more spohisticated copy to return something useful
size_t siz = pm->partitionMapLength;
pm = reinterpret_cast<PartitionMap*>( malloc( siz));
if (pm) {
    memcpy( pm, p, siz);
}
return pm;

答案 4 :(得分:0)

必须完成转换,但它使代码几乎不可读。为了便于阅读,请将其隔离在static inline函数中。

答案 5 :(得分:0)

让我感到困惑的是为什么你有'partitionMapLength'的字节数?

如果它是在“partitionMap”单位中会不会更好,因为你还是投了它?

PartitionMap *pmBase(reinterpret_cast<PartitionMap *>(partitionMaps));
PartitionMap *pm;
...
pm = pmBase + index; // just guessing about your 'index' variable here

答案 6 :(得分:0)

C和C ++都允许您通过指针和++迭代数组:

#include <iostream>

int[] arry = { 0, 1, 2, 3 };
int* ptr = arry;
while (*ptr != 3) {
    std::cout << *ptr << '\n';
    ++ptr;
}

为此,添加指针定义为获取存储在指针中的内存地址,然后添加sizeof,无论类型是添加值的类型。例如,在我们的示例中,++ptr1 * sizeof(int)添加到ptr中存储的内存地址。

如果你有一个指向某个类型的指针,并希望从该位置推进特定数量的字节,唯一的方法就是强制转换为char*(因为sizeof(char)被定义为是一个)。