perl:构建大/小端的大字段并用单个包输出它们

时间:2016-03-10 15:28:59

标签: perl bit-fields

我在perl中构建二进制数据。 该二进制数据基于C结构,用于32位和64位,大端和小端系统。 diffucult部分是FORMAT结构中的位域。这在小/大端架构的内存中有不同的布局。

我目前正在制作像这样的位域:

struct FORMAT
{
 void * X,
 void * Y,
 void * Z,
 unsigned int size   : 26;
 unsigned int type   :  6;
 <4 byte padding on 64bit targets>
}

my $size = 0x3C;
my $type = 0x05;

=> big endian
print pack("L>", $size << 6) | pack("L>", $type);  # 00 00 0f 05
=> little endian
print pack("L<", $size) | pack("L<", $type << 26); # 3c 00 00 14

但是我希望以单包形式提供上述内容(因此不会调用包两次,并且结果然后打印它。)

最终我想一次打印整个FORMAT记录。

 pack("Q>3L>L>", X, Y, Z, ???, 0) #64bit big endian

我有大约500k FORMAT记录需要写出来,并且每次记录多次调用pack()太昂贵了。

1 个答案:

答案 0 :(得分:1)

您可以使用XS。这将为您处理字节顺序和特定于编译器的对齐(填充)。

use strict;
use warnings;

use Inline C => <<'__EOC__';

   typedef struct {
      void* X;
      void* Y;
      void* Z;
      unsigned int size: 26;
      unsigned int type:  6;
   } FORMAT;

   SV* pack_FORMAT(UV X, UV Y, UV Z, unsigned int size, unsigned int type) {
      FORMAT format;
      format.X = INT2PTR(void*, X);
      format.Y = INT2PTR(void*, Y);
      format.Z = INT2PTR(void*, Z);
      format.size = size;
      format.type = type;
      return newSVpvn(&format, sizeof(format));
   }

__EOC__

my $size = 0x3C;
my $type = 0x05;

my $packed = pack_FORMAT(0, 0, 0, $size, $type);
printf("%v02X\n", $packed);

那说

pack("L>", $size << 6) | pack("L>", $type)
pack("L<", $size) | pack("L<", $type << 26)

可以写成

pack("L>", ($size << 6) | $type)
pack("L<", $size | ($type << 26))