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

发布于 2024-08-09 02:17:34 字数 603 浏览 2 评论 0原文

在以下代码行中,我需要将指针 pm 调整其字段之一中的字节偏移量。有没有更好/更简单的方法来做到这一点,而不是不断地从 char *PartitionMap * 来回转换,以使指针算术仍然有效?

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

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

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

In the following lines of code, I need to adjust the pointer pm by an offset in bytes in one of its fields. Is there an better/easier way to do this, than incessantly casting back and forth from char * and PartitionMap * such that the pointer arithmetic still works out?

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

For those that can't grok from the code, it's looping through variable length descriptors in a buffer that inherit from PartitionMap.

Also for those concerned, partitionMapLength always returns lengths that are supported by the system this runs on. The data I'm traversing conforms to the UDF specification.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

蒗幽 2024-08-16 02:17:34

我经常为此使用这些模板:

    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

I often use these templates for this:

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

They maintain the type, but add single bytes to them, for example:

T *x = add_pointer(x, 1); // increments x by one byte, regardless of the type of x
情绪失控 2024-08-16 02:17:34

强制转换是唯一的方法,无论是转换为 char* 或 intptr_t 还是其他此类类型,然后转换为最终类型。

Casting is the only way, whether it's to a char* or intptr_t or other some such type, and then to your final type.

只涨不跌 2024-08-16 02:17:34

当然,您可以只保留两个变量:一个用于单步执行缓冲区的 char * 和一个用于访问缓冲区的 PartitionMap *。让它更清楚发生了什么。

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

You can of course just keep two variables around: a char * to step through the buffer and a PartitionMap * to access it. Makes it a little clearer what's going on.

for (char *ptr = ??, pm = (PartitionMap *)ptr ; index > 0 ; --index)
{
    ptr += pm->partitionMapLength;
    pm = (PartitionMap *)ptr;
}
return pm;
厌味 2024-08-16 02:17:34

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

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;

As others have mentioned you need the casts, but you can hide the ugliness in a macro or function. However, one other thing to keep in mind is alignment requirements. On most processors you can't simply increment a pointer to a type by an arbitrary number of bytes and cast the result back into a pointer to the original type without problems accessing the struct through the new pointer due to misalignment.

One of the few architectures (even if it is about the most popular) that will let you get away with it is the x86 architecture. However, even if you're writing for Windows, you'll want to take this problem into account - Win64 does enforce alignment requirements.

So even accessing the partitionMapLength member through the pointer might crash your program.

You might be able to easily work around this problem using a compiler extension like __unaligned on Windows:

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

Or you can copy the potentially unaligned data into a properly aligned struct:

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;
白芷 2024-08-16 02:17:34

必须进行转换,但这会使代码几乎不可读。为了便于阅读,将其隔离在静态内联函数中。

The casting has to be done, but it makes the code nearly unreadable. For readability's sake, isolate it in a static inline function.

一生独一 2024-08-16 02:17:34

让我困惑的是为什么你有“partitionMapLength”(以字节为单位)?

如果它是在“partitionMap”单位中不是更好吗,因为你无论如何都会投射它?

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

What is puzzling me is why you have 'partitionMapLength' in bytes?

Wouldn't it be better if it was in 'partitionMap' units since you anyway cast it?

PartitionMap *pmBase(reinterpret_cast<PartitionMap *>(partitionMaps));
PartitionMap *pm;
...
pm = pmBase + index; // just guessing about your 'index' variable here
雪化雨蝶 2024-08-16 02:17:34

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

#include <iostream>

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

为此,定义添加到指针以获取存储在指针中的内存地址,然后添加任意值的大小。 type 是所添加的值的乘积。例如,在我们的示例中,++ptr1 * sizeof(int) 添加到 ptr 中存储的内存地址。

如果您有一个指向类型的指针,并且想要从该位置前进特定数量的字节,那么唯一的方法就是转换为 char* (因为 sizeof(char) 被定义为一)。

Both C and C++ allow you to iterate through an array via pointers and ++:

#include <iostream>

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

For this to work, adding to pointers is defined to take the memory address stored in the pointer and then add the sizeof whatever the type is times the value being added. For instance, in our example ++ptr adds 1 * sizeof(int) to the memory address stored in ptr.

If you have a pointer to a type, and want to advance a particular number of bytes from that spot, the only way to do so is to cast to char* (because sizeof(char) is defined to be one).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文