繁体   English   中英

返回给定 C 中的指针的 16 位

[英]Returning 16-bits given a pointer in C

一个块由一个 64 位长的 integer 表示,它被分成 4 个 16 位的部分。

我需要使用下面的 function 返回一个 16 位部分。

unsigned short get_16bitsection(unsigned long *start, int index) {
// Fill this in 
}

使用强制转换来实现这一点很诱人,但一个常见的误解是“一切都只是字节”,因此您可以安全地做到这一点。 一个称为严格别名的规则实际上禁止这样做。 您的代码可能看起来可以工作,特别是在较旧和不太复杂的编译器上,但在重度优化时代,您违反了这样的语言规则,实际上是在玩火。

相反,您应该将所需的字节复制uint16_t中,然后返回它:

uint16_t get_16bitsection(uint64_t *start, int index) {
  uint16_t result;
  memcpy(&result, (char*)start + index*sizeof(uint16_t), sizeof(uint16_t));
  return result;
}

在这里,我转换为char*以便我们可以按字节导航您的块(此别名是通常严格别名规则的特别允许的例外),然后应用index*sizeof(uint16_t)的偏移量以达到所需的索引(假设您已指定小端序)。 最后,我们将字节复制到result中,并返回它。

如果您担心性能,请不要担心。 您已经将uint16_t从本地 scope 复制到调用 scope 中; 刚才它有了名字。 如果这个 function混叠违规版本慢,那么这证明你已经混淆了优化器走得太远。

只需使用工会。

long int x=0x123456789abcdef0;

union {
    long int x;
    unsigned short arr[4];
} c;

c.x = x;
printf("%04x %04x %04x %04x\n", c.arr[0], c.arr[1], c.arr[2], c.arr[3]);

结果:

def0 9abc 5678 1234

给定指针返回 16 位
一个块由一个 64 位长的 integer 表示,它分为 4 个 16 位段

要以独立于字节序的可移植方式访问数据并检索 0:LS 16 位到 3:MS 16 位,请使用>>


由于unsigned long可能只有 32 位,建议使用unsigned long longuint_least64_t
考虑使指针const以允许此 function 用于const数据。

unsigned short get_16bitsection(const unsigned long long *start, int index) {
  #define MASK_16BIT 0xFFFFu
  return MASK_16BIT & (*start >> (16*index));
} 
  • 掩码在unsigned short不是 16 位的稀有机器上很有用。 IAC,我更喜欢面具而不是演员 - 减少范围的更温和的方式。
  • 或者使用强制转换: (unsigned short)(uint16_t)虽然这稍微不那么可移植,因为uint16_t可能不存在并且unsigned short可能 > 16 位。

也许我在这里错过了重点,但它可能就像这样简单:

unsigned short get_16bitsection_be(unsigned long *start, int index) {
  unsigned short *p = (unsigned short*) start;

  return p[3 - index];
}

unsigned short get_16bitsection_le(unsigned long *start, int index) {
  unsigned short *p = (unsigned short*) start;

  return p[index];
}

大端和小端之间的区别在这里是相关的。

请注意,您应该考虑使用stdint.h为这些类型赋予更有意义的名称,并明确您实际在做什么:

uint16_t get_16bitsection_le(uint64_t *start, int index) {
  uint16_t *p = (uint16_t*) start;

  return p[index];
}

uint16_t get_16bitsection_be(uint64_t *start, int index) {
  uint16_t *p = (uint16_t*) start;

  return p[3 - index];
}

您的第二种方法走在了正确的轨道上,但是该代码被许多无关紧要的东西弄得一团糟,再加上没有意义的* 8偏移量。

暂无
暂无

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

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