简体   繁体   English

是否可以在 C 中下标为 uint64_t 指针?

[英]Is it possible to subscript into a uint64_t pointer in C?

I'm a C beginner.我是C初学者。 Having trouble understanding whats happening with this code:无法理解这段代码发生了什么:

#include <stdio.h>
#include <stdint.h>

int main(void)
{
    uint64_t num = 99999;
    uint64_t *num_ptr = &num;

    uint8_t first_byte = ((uint8_t *)num_ptr)[0];

    printf("%hhu", first_byte);

    return 0;
}

This prints 159 .这将打印159

I'm looking at uint8_t first_byte = ((uint8_t *)num_ptr)[0];我在看uint8_t first_byte = ((uint8_t *)num_ptr)[0];

I'm trying to understand it this way: the uint64_t pointer num_ptr is first cast as a uint8_t pointer, then we index into it with the square brackets to get the first byte.我试图以这种方式理解它:首先将 uint64_t 指针num_ptr为 uint8_t 指针,然后我们用方括号对其进行索引以获取第一个字节。 Is this a correct explanation?这是一个正确的解释吗? If so is it possible to index into pointers to get their partial contents without dereferencing?如果是这样,是否可以在不取消引用的情况下索引指针以获取其部分内容?

Consider a work-alike program:考虑一个类似工作的程序:

#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%02x\n", number.parts[0], number.parts[0] );

    return 0;
}

Which outputs:哪个输出:

number.parts[0] is 159 / 0x9f

Here with a C union , it's simulating what was done in the OP's code.这里有一个C union ,它模拟了 OP 代码中所做的事情。 The .parts covers the same memory as the .whole . .parts覆盖与.whole相同的内存。 So in essence the parts is giving access to the content of the uint64_t 's bytes-in-memory without any sort of pointer dereference.所以本质上,这些parts是在没有任何类型的指针取消引用的情况下访问uint64_t的内存字节的内容。

This sort of operation will have issues with portability due to endianness , and should generally be avoided.由于字节顺序,这种操作会存在可移植性问题,通常应避免。 Of course one could mitigate this by packing into network-byte-order with functions like htonl() , so a known order is preserved.当然,可以通过使用htonl()之类的函数打包成网络字节顺序来缓解这种情况,因此保留了已知的顺序。

  • 99999 = 0x1869F or if you will as a 64 bit number 0000 0000 0001 869F 99999 = 0x1869F或者如果您将作为 64 位数字0000 0000 0001 869F
  • Intel/PC computers use little endian. Intel/PC 计算机使用小端序。 What is CPU endianness?什么是 CPU 字节序?
  • Therefore your 64 bit number is stored in memory as 9F86 0100 0000 0000 .因此,您的 64 位数字作为9F86 0100 0000 0000存储在内存中。
  • C allows us to inspect a larger data type byte by byte through a pointer to a character type. C 允许我们通过指向字符类型的指针逐字节检查更大的数据类型。 uint8_t is a character type on all non-exotic systems. uint8_t是所有非奇异系统上的字符类型。
  • ((uint8_t *)num_ptr)[0]; Converts the 64 bit pointer to a 8 bit (character) pointer and then uses the [] operator to de-reference that pointer.将 64 位指针转换为 8 位(字符)指针,然后使用[]运算符取消引用该指针。
  • We get the first byte 0x9F = 159 dec.我们得到第一个字节0x9F = 159 dec。
  • %hhu is used to print unsigned char . %hhu用于打印unsigned char The most correct conversion specifier to use for uint8_t would otherwise be "%" PRIU8 from inttypes.h用于uint8_t的最正确转换说明符将是inttypes.h中的"%" PRIU8
  1. What you do is a "pointer punning".你所做的是“指针双关语”。 Generally it is a dangerous operation, might invoke Undefined Behavior and violate strict aliasing rule.通常这是一个危险的操作,可能会调用未定义的行为并违反严格的别名规则。 But when you access other data as char s it is OK.但是,当您以char的形式访问其他数据时,就可以了。
int main(void)
{
    uint64_t num = 99999;
    uint64_t *num_ptr = &num;

    printf("%016"PRIx64"\n", num);

    for(size_t index = 0; index < sizeof(num); index++)
    {
        printf("Index = %2zu, value= %02hhx\n", index, ((unsigned char *)num_ptr)[index]);
    }
    return 0;
}

The safest method is to use memcpy最安全的方法是使用memcpy

int main(void)
{
    uint64_t num = 99999;
    uint64_t *num_ptr = &num;

    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= %02hhx\n", index, arr[index]);
    }
    return 0;
}

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

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