[英]What is *(uint32_t *) &buffer[index]?
In some supposed-C++ code I found, I have buffer
defined as const void *buffer;
在我发现的一些假定的C ++代码中,我将
buffer
定义为const void *buffer;
(it's arbitrary binary data that, I think, gets interpreted as a stream of 32-bit unsigned integers) and in many places, I have (我认为它是任意二进制数据,被解释为32位无符号整数的流),并且在许多地方,
*(uint32_t *) &buffer[index]
where index
is some kind of integer (I think it was long
or unsigned long
and got swept up in my replacing those with int32_t
and uint32_t
when I was making the code work on a 64-bit system). 其中
index
是某种整数(我认为它是long
或unsigned long
并且在使代码在64位系统上工作时,被int32_t
和uint32_t
取代)。
I recognize that this is taking the address of buffer
( &buffer
), casting it as a pointer to a uint32_t
, and dereferencing that, at least based on this question ... but then I'm confused by how the [index]
part interacts with that or where I missed inserting the [index]
part in between the steps I listed. 我认识到这至少是基于这个问题 ,它采用
buffer
( &buffer
)的地址,将其转换为指向uint32_t
的指针,并对其进行解引用...但是然后,我对[index]
部分的交互方式感到困惑这样,或者我错过了在列出的步骤之间插入[index]
部分的位置。
What, conceptually, is this doing? 从概念上讲,这是做什么的? Is there some way I could define another variable to be a better type, with the casting there once, and then use that, rather than having this complicated expression throughout the code?
我是否可以通过某种方式将另一个变量定义为更好的类型,并在其中进行一次转换,然后使用该变量,而不是在整个代码中使用这种复杂的表达式? Is this actually C++ or is this C99?
这实际上是C ++还是C99?
edit: The first couple of lines of the code are: 编辑:代码的前几行是:
const void *buffer = data.bytes;
if (ntohl(*(int32_t *) buffer) != 'ttcf') {
return;
}
uint32_t ttf_count = ntohl(*(uint32_t *) &buffer[0x08]);
where data.bytes
has type const void *
. 其中
data.bytes
类型为const void *
。 Before I was getting buffer
from data.bytes
, it was char *
. 在我从
data.bytes
获取buffer
data.bytes
,它是char *
。
edit 2: Apparently, having const void *buffer
work is not normal C (though it absolutely works in my situation), so if it makes more sense, assume it's const char *buffer
. 编辑2:显然,使
const void *buffer
工作不是正常的C(尽管在我的情况下绝对可行),因此,如果更有意义,则假定它为const char *buffer
。
Putting parenthesis in place to make the order of operations more explicit: 放置括号以使操作顺序更明确:
*((uint32_t *) &(buffer[index]))
So you're treating buffer
as an array, however because buffer
is a void *
you can't dereference it directly. 因此,您将
buffer
视为数组,但是由于buffer
是void *
,因此无法直接取消引用它。
Assuming you want to treat this buffer as an array of uint32_t
, what you want to do is this: 假设您要将此缓冲区视为
uint32_t
数组,则需要执行以下操作:
((uint32_t *)buffer)[index]
Which can also be written as: 也可以写成:
*((uint32_t *)buffer + index)
EDIT: 编辑:
If index
is the byte offset in the buffer, that changes things. 如果
index
是缓冲区中的字节偏移,那将改变情况。 In that case, I'd recommend defining the buffer as const char *
instead of const void *
. 在这种情况下,我建议将缓冲区定义为
const char *
而不是const void *
。 That way, you can be sure the dereferencing of the array is working properly. 这样,您可以确保数组的取消引用工作正常。
So to break down the expression: 因此,要分解表达式:
*(uint32_t *) &buffer[index]
You're going index
bytes into buffer
: buffer[index]
您要将
index
字节放入buffer
: buffer[index]
Then taking the address of that byte: &buffer[index]
然后获取该字节的地址:
&buffer[index]
Then casting that address to a uint32_t
: (uint32_t *) &buffer[index]
然后将该地址转换为
uint32_t
: (uint32_t *) &buffer[index]
Then dereferencing the uint32_t
value: *(uint32_t *) &buffer[index]
然后取消引用
uint32_t
值: *(uint32_t *) &buffer[index]
Lots of issues here! 这里有很多问题! First of all, a
void *
cannot be dereferenced. 首先,
void *
无法取消引用。 buffer[index]
is illegal in ISO C, although some compilers apparently have an extension that will treat it as (void)((char *)buffer)[index]
. 尽管某些编译器显然具有将其视为
(void)((char *)buffer)[index]
的扩展名,但buffer[index]
在ISO C中是非法的。
You suggest in comments that the code originally used char *
- I recommend you leave it that way. 您在注释中建议该代码最初使用
char *
-我建议您采用这种方式。 Assuming buffer
returns to being const char *
: 假设
buffer
返回为const char *
:
if (ntohl(*(int32_t *) buffer) != 'ttcf') { return; }
The intent here is to pretend that the first four bytes of buffer
contain an integer; 这里的目的是假装
buffer
的前四个字节包含一个整数。 read that integer, and compare it to 'ttcf'
. 读取该整数,并将其与
'ttcf'
进行比较。 The latter is a multibyte character constant, the behaviour of which is implementation-defined . 后者是一个多字节字符常量,其行为是实现定义的 。 It could represent four characters
't', 't', 'c', 'f'
, or 'f', 'c', 't', 't'
, or in fact anything else at all of type int
. 它可以表示四个字符
't', 't', 'c', 'f'
或'f', 'c', 't', 't'
或int
类型的所有其他字符。
A greater problem is that pretending a buffer contains an int
when it did not actually get written via an expression of type int
violates the strict aliasing rule . 更大的问题是,假装缓冲区包含一个
int
时,它实际上并没有得到通过类型的表达式书面int
违反了严格别名规则 。 This is unfortunately a common technique in older code, but even since the first C standard it has caused undefined behaviour. 不幸的是,这是较旧代码中的常见技术,但是即使自第一个C标准以来,它也导致了不确定的行为。 If you use a compiler that performs type-based aliasing optimization it could wreck your code.
如果您使用执行基于类型的别名优化的编译器,则可能会破坏您的代码。
A way to write this code avoiding both of those problems is: 编写此代码来避免这两个问题的方法是:
if ( memcmp(buffer, "ttcf", 4) ) { return; }
The later line uint32_t ttf_count = ntohl(*(uint32_t *) &buffer[0x08]);
后面的行
uint32_t ttf_count = ntohl(*(uint32_t *) &buffer[0x08]);
has similar issues. 有类似的问题。 In this case there is no doubt that the best fix is:
在这种情况下,毫无疑问,最佳解决方案是:
uint32_t ttf_count;
memcpy(&ttf_count, buffer + 0x08, sizeof ttf_count);
ttf_count = ntohl(ttf_count);
As discussed in comments, you could make an inline function to keep this tidy. 如评论中所述,您可以内联函数以保持整洁。 In my own code I do something like:
在我自己的代码中,我执行以下操作:
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];
}
and a similar version le_to_uint32
that reads bytes in the opposite order; 和类似的版本
le_to_uint32
以相反的顺序读取字节; then I use whichever of those corresponds to the input format instead of using ntohl
. 然后我使用与输入格式相对应的任何一种,而不是使用
ntohl
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.