来自NSData的objective-c sscanf

时间:2014-10-26 18:04:17

标签: objective-c bit-shift scanf

我有一个BTLE设备,它向我发送字节,其中一些我需要组成一个32位有符号的int,转换,然后解释。我正在使用xcode 6.1。

我遇到的问题是使用sscanf简单地将字节转换为int32_t,这有时可以工作,有时却不能。我不是一个obj-c专家,不确定这是否是正确的方法,使用strtol同样不起作用。

整个功能如下:

- (double) parseMV2: (NSData*) data {
  NSData* slicedData = [data subdataWithRange:NSMakeRange(2, 4)];
  const char *bytes = [slicedData bytes];
  int32_t value;
  double mV = 0;

  int sscanf_result = sscanf(bytes, "%4x", &value);

  if (1 == sscanf_result) {
    value <<= 3; // discard the 3 most significant bits as they are not part of the value this also brings the sign bit to the most significant bit position.
    value >>= 8; // discard the 5 least significant bits as they are below the noise levels.
    mV = ((double)value)*2048.0/16777216.0; // Convert to mV
  } else {
    NSLog(@" sscanf failed to read bytes %4x (result = %d)", (int32_t) bytes, sscanf_result);
  }

  NSLog(@"     mV2 = %f (bytes = %x", mV, (uint) bytes);
  NSLog(@"----------------------------------");

  return mV;
}

如果我在sscanf之后设置断点,有时将值设置为正确的字节解释,但通常只设置为零。这是llvm的一些输出:

(lldb) print bytes
(const char *) $3 = 0x17ecceb8 "+\333\x91"
(lldb) print value
(int32_t) $4 = 0

这是另一个例子,其中sscanf再次返回0但值不为0(因为我认为sscanf返回它实际指定的变量数量,所以不要这样做):

(lldb) print bytes
(const char *) $6 = 0x176db558 ")Z\x19x"
(lldb) print value
(int32_t) $7 = 383772

1 个答案:

答案 0 :(得分:4)

使用sscanf用于从C字符串中读取,但您没有C字符串。你有一个字节序列。

以这种方式尝试:

NSData* slicedData = [data subdataWithRange:NSMakeRange(2, 4)];
const uint8_t *bytes = [slicedData bytes];
int32_t value;
memcpy(&value, bytes, 4);

正如Ken所指出的,更简单的方法是:

int32_t value;
[data getBytes:&value range:NSMakeRange(2, 4)];

您可能还需要担心字节排序,具体取决于数据的创建方式。您可能需要添加:

value = CFSwapInt32BigToHost(value); // or CFSwapInt32LittleToHost