用于使用字节偏移进行操作的更清晰的指针算术语法
-
06-07-2019 - |
题
在下面的代码行中,我需要在其中一个字段中按字节偏移量调整指针 pm
。有没有更好/更简单的方法来做这件事,而不是从 char *
和 PartitionMap *
来回不断地来回转换,这样指针算法仍然有效?
PartitionMap *pm(reinterpret_cast<PartitionMap *>(partitionMaps));
for ( ; index > 0 ; --index)
{
pm = (PartitionMap *)(((char *)pm) + pm->partitionMapLength);
}
return pm;
对于那些无法从代码中删除的人,它会循环遍历从 PartitionMap
继承的缓冲区中的可变长度描述符。
对于那些有关的人,partitionMapLength总是返回运行它的系统支持的长度。我正在遍历的数据符合 UDF 规范。
解决方案
我经常使用这些模板:
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
其他提示
Casting是唯一的方法,无论是char *或intptr_t还是其他类型的,然后是你的最终类型。
你当然可以保留两个变量:一个 char *
来逐步执行缓冲区,一个 PartitionMap *
来访问它。让事情变得更加清晰。
for (char *ptr = ??, pm = (PartitionMap *)ptr ; index > 0 ; --index)
{
ptr += pm->partitionMapLength;
pm = (PartitionMap *)ptr;
}
return pm;
正如其他人所说,你需要演员,但你可以隐藏宏观或功能中的丑陋。但是,要记住的另一件事是对齐要求。在大多数处理器上,您不能简单地将指针增加到任意数量的字节,并将结果转换回指向原始类型的指针,而不会因为未对齐而通过新指针访问结构。
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;
必须完成转换,但它使代码几乎不可读。为了便于阅读,请将其隔离在静态内联
函数中。
让我感到困惑的是为什么你有'partitionMapLength'的字节数?
如果它是在“partitionMap”单位中会不会更好,因为你还是投了它?
PartitionMap *pmBase(reinterpret_cast<PartitionMap *>(partitionMaps));
PartitionMap *pm;
...
pm = pmBase + index; // just guessing about your 'index' variable here
C和C ++都允许您通过指针和 ++
遍历数组:
#include <iostream>
int[] arry = { 0, 1, 2, 3 };
int* ptr = arry;
while (*ptr != 3) {
std::cout << *ptr << '\n';
++ptr;
}
为此,添加指针定义为获取存储在指针中的内存地址,然后添加sizeof,无论类型是添加值的类型。例如,在我们的示例中, ++ ptr
将 1 * sizeof(int)
添加到 ptr
中存储的内存地址。
如果你有一个指向某个类型的指针,并希望从该位置推进特定数量的字节,那么唯一的方法是转换为 char *
(因为 sizeof (char)
被定义为one)。