具有未确定字节数的小端到uint

时间:2018-03-19 02:42:03

标签: c endianness

我正在尝试编写一个函数,该函数接受N个字节的小字节十六进制并使其成为无符号整数。

unsigned int endian_to_uint(char* buf, int num_bytes)
{
    if (num_bytes == 0)
            return (unsigned int) buf[0];

    return (((unsigned int) buf[num_bytes -1]) << num_bytes * 8) | endian_to_uint(buf, num_bytes - 1);
}

但是,返回的值比预期值大约约256倍。那是为什么?

如果我需要将它用于4字节缓冲区,通常你会这样做:

unsigned int endian_to_uint32(char* buf)
{
    return (((unsigned int) buf[3]) <<   24)
         | (((unsigned int) buf[2]) <<   16)
         | (((unsigned int) buf[1]) << 8)
         | (((unsigned int) buf[0]));
}

哪个应该由我写的递归函数重现,还是有一些我没有被捕获的算术错误?

2 个答案:

答案 0 :(得分:0)

以下代码段可行。

unsigned int endian_to_uint(unsigned char* buf, int num_bytes)
{
    if (num_bytes == 0)
        return (unsigned int) buf[0];

    return (((unsigned int) buf[num_bytes -1]) << (num_bytes -1) * 8) | endian_to_uint(buf, num_bytes - 1);
}

改变1:
修改了从char*unsigned char *的函数参数数据类型 原因:
对于给定的buf[] = {0x12, 0x34, 0xab, 0xcd};
当您尝试阅读buf[3]时,buf[num_bytes -1]会因为符号扩展而向0xffffffcd而不仅仅0xcd提供num_bytes-1。有关签名扩展的详细信息,请参阅Sign Extension

更改2:
计算换档位置值时使用<ul> <li><img src="test.img" alt=""></li> <li><p>text</p></li> <li><p>text2</p></li> </ul> <ul> <li><p>text</p></li> <li><img src="test.img" alt=""></li> <li><p>text2</p></li> </ul> 。这是计算要移位的位数的逻辑错误。

答案 1 :(得分:0)

这里绝对没有理由使用递归:位移是最快的可用操作之一,递归是最慢的。此外,递归是危险的,难以阅读并且给出令人讨厌的峰值堆栈消耗。一般情况下应该避免。

此外,您的功能不是一般的功能,因为您返回unsigned int,使功能在每一种方式都不如移位版本。

要实际编写一个通用大小的小端转换函数,你可以这样做:

void little_endian (size_t bytes, uint8_t dest[bytes], const uint8_t src[bytes])
{
  for(size_t i=0; i<bytes; i++)
  {
    dest[i] = src[bytes-i-1];
  }
}

工作示例:

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


void little_endian (size_t bytes, uint8_t dest[bytes], const uint8_t src[bytes])
{
  for(size_t i=0; i<bytes; i++)
  {
    dest[i] = src[bytes-i-1];
  }
}

int main (void)
{
  uint8_t data [] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
  uint32_t u32;
  uint64_t u64;

  little_endian(4, (uint8_t*)&u32, data);
  little_endian(8, (uint8_t*)&u64, data);

  printf("%"PRIx32"\n", u32);
  printf("%"PRIx64"\n", u64);

  return 0;
}