繁体   English   中英

*(uint32_t *)&buffer [index]是什么?

[英]What is *(uint32_t *) &buffer[index]?

在我发现的一些假定的C ++代码中,我将buffer定义为const void *buffer; (我认为它是任意二进制数据,被解释为32位无符号整数的流),并且在许多地方,

*(uint32_t *) &buffer[index]

其中index是某种整数(我认为它是longunsigned long并且在使代码在64位系统上工作时,被int32_tuint32_t取代)。

我认识到这至少是基于这个问题 ,它采用buffer&buffer )的地址,将其转换为指向uint32_t的指针,并对其进行解引用...但是然后,我对[index]部分的交互方式感到困惑这样,或者我错过了在列出的步骤之间插入[index]部分的位置。

从概念上讲,这是做什么的? 我是否可以通过某种方式将另一个变量定义为更好的类型,并在其中进行一次转换,然后使用该变量,而不是在整个代码中使用这种复杂的表达式? 这实际上是C ++还是C99?

编辑:代码的前几行是:

const void *buffer = data.bytes;
if (ntohl(*(int32_t *) buffer) != 'ttcf') {
    return;
}
uint32_t ttf_count = ntohl(*(uint32_t *) &buffer[0x08]);

其中data.bytes类型为const void * 在我从data.bytes获取buffer data.bytes ,它是char *

编辑2:显然,使const void *buffer工作不是正常的C(尽管在我的情况下绝对可行),因此,如果更有意义,则假定它为const char *buffer

放置括号以使操作顺序更明确:

*((uint32_t *) &(buffer[index]))

因此,您将buffer视为数组,但是由于buffervoid * ,因此无法直接取消引用它。

假设您要将此缓冲区视为uint32_t数组,则需要执行以下操作:

((uint32_t *)buffer)[index]

也可以写成:

*((uint32_t *)buffer + index)

编辑:

如果index是缓冲区中的字节偏移,那将改变情况。 在这种情况下,我建议将缓冲区定义为const char *而不是const void * 这样,您可以确保数组的取消引用工作正常。

因此,要分解表达式:

*(uint32_t *) &buffer[index]

您要将index字节放入bufferbuffer[index]

然后获取该字节的地址: &buffer[index]

然后将该地址转换为uint32_t(uint32_t *) &buffer[index]

然后取消引用uint32_t值: *(uint32_t *) &buffer[index]

这里有很多问题! 首先, void *无法取消引用。 尽管某些编译器显然具有将其视为(void)((char *)buffer)[index]的扩展名,但buffer[index]在ISO C中是非法的。

您在注释中建议该代码最初使用char * -我建议您采用这种方式。 假设buffer返回为const char *

if (ntohl(*(int32_t *) buffer) != 'ttcf') { return; }

这里的目的是假装buffer的前四个字节包含一个整数。 读取该整数,并将其与'ttcf'进行比较。 后者是一个多字节字符常量,其行为是实现定义的 它可以表示四个字符't', 't', 'c', 'f''f', 'c', 't', 't'int类型的所有其他字符。

更大的问题是,假装缓冲区包含一个int时,它实际上并没有得到通过类型的表达式书面int违反了严格别名规则 不幸的是,这是较旧代码中的常见技术,但是即使自第一个C标准以来,它也导致了不确定的行为。 如果您使用执行基于类型的别名优化的编译器,则可能会破坏您的代码。

编写此代码来避免这两个问题的方法是:

if ( memcmp(buffer, "ttcf", 4) ) { return; }

后面的行uint32_t ttf_count = ntohl(*(uint32_t *) &buffer[0x08]); 有类似的问题。 在这种情况下,毫无疑问,最佳解决方案是:

uint32_t ttf_count; 
memcpy(&ttf_count, buffer + 0x08, sizeof ttf_count);
ttf_count = ntohl(ttf_count);

如评论中所述,您可以内联函数以保持整洁。 在我自己的代码中,我执行以下操作:

static inline uint32_t be_to_uint32(void const *ptr)
{
    unsigned char const *p = ptr;
    return p[0] * 0x1000000ul + p[1] * 0x10000ul + p[2] * 0x100 + p[3];
}

和类似的版本le_to_uint32以相反的顺序读取字节; 然后我使用与输入格式相对应的任何一种,而不是使用ntohl

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM