我是一个C初学者。无法理解这段代码的含义:
#include <stdio.h>
#include <stdint.h>
int main(void)
{
uint64_t num = 99999;
uint64_t *num_ptr = #
uint8_t first_byte = ((uint8_t *)num_ptr)[0];
printf("%hhu", first_byte);
return 0;
}
打印159
。
我在看uint8_t first_byte = ((uint8_t *)num_ptr)[0];
我试图这样理解它:uint64_t指针num_ptr
首先被转换为uint8_t指针,然后我们用方括号索引它以获得第一个字节。这个解释正确吗?如果是这样,是否有可能索引到指针,以获得他们的部分内容没有解引用?
99999
=0x1869F
或者如果您愿意,则为64位数字0000 0000 0001 869F
- Intel/PC电脑使用小端序。什么是CPU端序? 因此,您的64位数字存储在内存中为
- C允许我们通过指向字符类型的指针逐字节地检查更大的数据类型。
uint8_t
是所有非外来系统的字符类型。 ((uint8_t *)num_ptr)[0];
将64位指针转换为8位(字符)指针,然后使用[]
运算符对该指针进行解引用。- 我们得到第一个字节
0x9F
= 159 dec %hhu
用于打印unsigned char
。uint8_t
最正确的转换说明符应该是inttypes.h
中的
9F86 0100 0000 0000
。"%" PRIU8
。考虑一个类似工作的程序:
#include <stdio.h>
#include <stdint.h>
typedef union td_USixtyFour
{
uint64_t whole;
uint8_t parts[sizeof(uint64_t)];
} USixtyFour;
int main( int argc, char **argv )
{
USixtyFour number;
number.whole = 99999;
printf( "number.parts[0] is %u / 0x%02xn", number.parts[0], number.parts[0] );
return 0;
}
输出:
number.parts[0] is 159 / 0x9f
在这里使用C联合,它模拟了OP代码中的操作。.parts
与.whole
覆盖相同的内存。因此,本质上,parts
允许访问uint64_t
的内存字节,而不需要任何类型的指针解引用。
这类操作会因为端序而导致可移植性问题,通常应该避免。当然,可以通过使用htonl()
之类的函数将其打包成网络字节顺序来缓解这种情况,这样就保留了已知的顺序。
- 你所做的是一个"指针双关语"。通常这是一个危险的操作,可能会调用未定义行为并违反严格的混叠规则。但是当您访问其他数据作为
char
s时,它是OK的。
int main(void)
{
uint64_t num = 99999;
uint64_t *num_ptr = #
printf("%016"PRIx64"n", num);
for(size_t index = 0; index < sizeof(num); index++)
{
printf("Index = %2zu, value= %02hhxn", index, ((unsigned char *)num_ptr)[index]);
}
return 0;
}
最安全的方法是使用memcpy
int main(void)
{
uint64_t num = 99999;
uint64_t *num_ptr = #
unsigned char arr[sizeof(num)];
printf("%016"PRIx64"n", num);
memcpy(arr, &num, sizeof(num));
for(size_t index = 0; index < sizeof(num); index++)
{
printf("Index = %2zu, value= %02hhxn", index, arr[index]);
}
return 0;
}