Perl打开包装" S *"相当于C

时间:2015-01-21 04:39:53

标签: c perl

我正在理解Perl在我正在阅读的一些代码中解压缩,特别是使用S*模板。

$data = "FF";
print "$data - ", unpack("S*", $data), "\n";
# > FF - 17990
  1. C中的相应内容是什么?
  2. 为什么?
  3. 非常感谢你的帮助

3 个答案:

答案 0 :(得分:3)

你在C中的代码看起来(大致)是这样的:

const char *data = "FA";
unsigned short s;
memcpy( &s, data, strlen(data) );
printf("%s = %d\n", data, s);

这只处理你的情况有两个字符,而解包('S *',...)将返回与其输入对应的短裤列表。

为什么呢?打包和解包的主要动机之一是使用C结构更容易地交换二进制数据。

perlpacktut是一个很好的起点。

答案 1 :(得分:3)

unpack 'S'将两个字节转换为uint16_t

#include <stdint.h>
const char *data = "\x46\x41";
uint16_t n;
memcpy(&n, data, sizeof(n));  // n = 0x4146 or 0x4641

在执行此操作之前,请不要忘记检查data中的字节数!


请注意,它可以根据系统提供两种不同的结果。

在小端系统(例如x86,x64)上,unpack 'S'也相当于

uint16_t n = (data[1] << 8) | data[0];  // 0x4146

在大端系统上,unpack 'S'也等同于

uint16_t n = (data[0] << 8) | data[1];  // 0x4641

顺便说一句,您可能会尝试执行以下操作,但由于内存对齐问题,它无法移植:

uint16_t n = *((const uint16_t *)data);

答案 2 :(得分:1)

我正在回答我自己的问题,所以我可能会遇到一些问题,但是我会把它留在这里给将来的任何人。

首先,让我的例子改为

$data = "FA";
print "$data - ", unpack("S*", $data), "\n";
# > FA - 16710

因为“FF”并没有特别的帮助。

问题是:我们是如何从“FA”到16710的?

首先,将字符“F”转换为ASCII值-70。在二进制中,这是0100 0110(请注意,我填充了一个前导零,因此很明显它是一个完整的字节)。

然后,我们需要'A'-65的ASCII值。二进制,0100 0001

因此,我们F对应0100 0110A对应0100 0001

然后我们将这两个二进制值粘合在一起,除了我们首先放置A

0100 0001 0100 0110

0100 0001 0100 0110转换为十进制会产生16,710

注意:我认为字节粘在一起的顺序可能在不同的计算机上有所不同,所以虽然这里的原则应该适用于所有地方,但数字可能是不同。