手動將 C 結構轉換為包語法
如果你從 Perl 程式碼處理 C 二進位制 API,通過 syscall
,ioctl
或 fcntl
函式,你需要知道如何以 C 相容的方式構造記憶體。
例如,如果你曾經處理過一些期望一個 timespec
的函式,你會看到/usr/include/time.h
並找到:
struct timespec
{
__time_t tv_sec; /* Seconds. */
__syscall_slong_t tv_nsec; /* Nanoseconds. */
};
你和 cpp
一起跳舞,找到真正含義的東西:
cpp -E /usr/include/time.h -o /dev/stdout | grep __time_t
# typedef long int __time_t;
cpp -E /usr/include/time.h -o /dev/stdout | grep __syscall_slong_t
# typedef long int __syscall_slong_t
所以它是一個(簽名的)int
echo 'void main(){ printf("%#lx\n", sizeof(__syscall_slong_t)); }' |
gcc -x c -include stdio.h -include time.h - -o /tmp/a.out && /tmp/a.out
# 0x8
它需要 8 個位元組。所以 64bit 簽了 int。而我正在使用 64 位處理器。 =)
Perldoc pack
說
q A signed quad (64-bit) value.
所以打包一個 timespec:
sub packtime {
my ( $config ) = @_;
return pack 'qq', @{$config}{qw( tv_sec tv_nsec )};
}
並開啟一個 timespec:
sub unpacktime {
my ( $buf ) = @_;
my $out = {};
@{$out}{qw( tv_sec tv_nsec )} = unpack 'qq', $buf;
return $out;
}
現在你可以使用這些功能。
my $timespec = packtime({ tv_sec => 0, tv_nsec => 0 });
syscall( ..., $timespec ); # some syscall that reads timespec
later ...
syscall( ..., $timespec ); # some syscall that writes timespec
print Dumper( unpacktime( $timespec ));