在c / objective-c中将原始字节转换为基本类型?

时间:2015-04-16 20:08:23

标签: objective-c byte nsdata primitive

我在NSData对象中有一些字节。

我想将前四个字节转换为无符号大端int。

接下来的2个成为无符号的大端短,接下来的4个成为无符号的大端长。

一般来说,我需要弄清楚如何将字符串分解为我期望的任何原始类型。

这是我从前4个字节获取int的最佳尝试:

int position = 0;
const unsigned char *firstFourBytes;
[stream getBytes:&firstFourBytes range:NSMakeRange(position , 4)];
uint32_t test = *(uint32_t*)firstFourBytes;
position+=4;

有谁能告诉我这样做的最佳方法?谢谢!

1 个答案:

答案 0 :(得分:1)

您拥有的代码不正确:

int position = 0;
const unsigned char *firstFourBytes;

在您声明firstFourBytes作为指针之上,您有分配了一个可容纳4个字节的缓冲区,firstFourBytes本身未初始化

[stream getBytes:&firstFourBytes range:NSMakeRange(position , 4)];

getBytes:range:需要一个指向缓冲区的指针,它可以将字节复制到该缓冲区中。您传递&firstFourBytes,它是指向用于变量firstFourBytes的存储的指针,因此您要求将字节复制到firstFourBytes所指向的缓冲区中,而不是{{1}本身。幸运的是,你只要求4个字节,firstFourBytes是4个(32位软件)或8个(64位软件)字节,所以字节适合......

sizeof(unsigned char *)

但是你现在拿这四个字节,这是你的大端4字节整数,并使用它们(如果是64位,还有4个额外的垃圾字节)作为指向内存的指针,并尝试从中读取一个四字节整数随机位置。 可能工作并返回垃圾,它可能会崩溃。

uint32_t test = *(uint32_t*)firstFourBytes;

如何操作

你需要:

  1. 适当大小的缓冲区。
  2. 要使此缓冲区正确对齐您正在阅读的数据类型,例如对于32位数据,缓冲区通常应位于四字节边界上。 (这不是绝对的要求,某些平台支持关闭对齐存储和加载,但如果是这样,通常要慢得多。)
  3. 从big-endian转换为计算机使用的任何内容。
  4. 解决(1)和(2)的最简单方法是声明所需类型的变量 - 编译器将处理对齐,(Objective-)C允许您获取任何变量的地址并将其用作一个字节缓冲区。所以你从:

    开始
    position+=4;
    

    现在可以通过将其视为字节缓冲区来直接读取所需的字节数:

    UInt32 uint32bytes;
    

    注意:必须检查提供的范围是否在[stream getBytes:&uint32bytes range:NSMakeRange(position, sizeof(UInt32)) ]; 之内,因为stream如果不是getBytes:range:将会引发异常。

    现在你在uint32bytes中有4个字节,但是它们是big-endian顺序,你的平台可能是little-endian(就像x86一样)。为了解决这个问题,Apple提供了Byte Order Utilities,这是一组函数,用于在字节序格式之间转换不同大小的数据。您正在寻找的函数是CFSwapInt32BigToHost,它可以从big-endian转换为您的平台(主机)使用的任何东西 - 所以在大端平台上它什么都不做,在小端平台上它交换字节。所以你现在可以:

    UInt32 result = CFSwapInt32BigToHost(uint32bytes);
    

    你有结果。

    您可以将此模板应用于其他类型,例如UInt16,以及使用字节顺序实用程序中的相应功能。

    HTH