在C中访问数组的连续条目

时间:2015-12-26 06:04:45

标签: c pointers void-pointers

假设我有这个:

uint8_t a[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};

如果我:

printf("%lu", ((uint64_t*) a)[0]);

我会得到:

0x0102030405060708

如何使用非标准尺寸进行此操作?恩。 ((uint94_t) a)[0]。 当然,没有uint94_t,这就是我所要求的。如何读取非标准位数(甚至是字节,它也能为我完成工作)?

注意:我不关心printf的特定字符串(因此它可以解析非标准数量的位/字节)但是在数据类型中

2 个答案:

答案 0 :(得分:2)

"%ul"表示"%u"(unsigned int),后跟字母"l"。也许您打算"%lu"(无符号长整数),但这两个对uint64_t都不正确。

inttypes.h中找到了正确的说明符,它是"%" PRIu64

这也不会按照你的建议打印0x,它会打印一个十进制表示。使用"%" PRIx64表示十六进制表示(也不会打印前导0x)。

继续,您的代码会导致undefined behaviour。根据严格别名规则,不允许使用uint64_t类型的表达式来访问首先未写为uint64_tint64_t的任何变量。

您可以通过使用正确类型的变量来避免严格别名规则,无论是在联合中还是其他方式,例如:

uint64_t x;
memcpy(&x, a, sizeof x);
printf("%" PRIu64 "\n", x);

您的编译器将对此进行优化,因此不要担心它效率低下或其他什么。

请注意,这是实现定义的的输出,因为编译器可以选择各种方式对uint64_t的位进行排序。两个常见订单是 big-endian little-endian

你问题的另一部分是关于其他整数类型。不幸的是,你坚持使用编译器提供的东西。很可能它没有提供uint94_t。你必须推出自己的代码来实现你想要的。例如,您可以模拟96位大端:

uint8_t a[12] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C};

uint64_t x = 0, y = 0;
mempcy((unsigned char *)&x + 4, a, 4); 
memcpy(&y, a+4, 8);
printf("%" PRIx64 "%" PRIx64 "\n", x, y);

当然你可以逐个字符地打印它。

答案 1 :(得分:0)

一点点谷歌搜索给了我答案...... 答案是位域!

typedef union {
    __uint128_t i : 96;
} __attribute__((packed)) uint96_t;
printf("%ul", ((uint96_t*) a)[0]);