13

Perlではpackunpackバイトを16進数に変換するための2つのテンプレートがあります。

h    16進文字列(最初に低いニブル)。
H    16進文字列(最初に高ニブル)。

これは、例を使用して最も明確になります。

use 5.010; # so I can use say
my $buf = "\x12\x34\x56\x78";

say unpack('H*', $buf); # prints 12345678
say unpack('h*', $buf); # prints 21436587

ご覧のとおり、Hバイトを16進数に変換したり、16進数から変換したりすることを考えると、一般的にはこのようになります。では、その目的はh何ですか?ラリーは誰かがそれを使うかもしれないと思っていたに違いありません、さもなければ彼はそれを含めることを気にしなかっただろう。

hまたはの代わりにH実際に使用したい実際の例を挙げていただけますpackunpack 具体的な例を探しています。そのようなバイトを編成したマシンを知っている場合、それは何でしたか、そしてそのドキュメントにリンクできますか?

フォーマットが何であるかを気にしないときにデータをシリアル化するなど、読み戻すことができる限り、使用 できる例を考えることができますが、その場合も同様に役立ちます。よりも便利な例を探しています。hHhH

4

3 に答える 3

12

MS-DOSの悪い時代に、レジスタに高ニブルと低ニブルを設定し、Interuptxxを実行することによって特定のOS機能が制御されていたことを思い出してください。たとえば、Int21は多くのファイル関数にアクセスしました。あなたはドライブ番号として高いニブルを設定します-誰が15以上のドライブを持っていますか?そのドライブで要求された機能としての低ニブルなど。

これは、MS-DOSシステムコールを実行するようにレジスタを設定するために説明するようにpackを使用する古いCPANコードです

Blech !!! 私はMS-DOSをまったく見逃していません...

- 編集

具体的なソースコードは次のとおりです。DOS用のPerl5.00402をここからダウンロードし解凍し、

ファイルOpcode.pmおよびOpcode.plには、次の使用法が記載unpack("h*",$_[0]);されています。

sub opset_to_hex ($) {
    return "(invalid opset)" unless verify_opset($_[0]);
    unpack("h*",$_[0]);
}

私はコードを最後までたどりませんでしたが、私の疑いは、これがMS-DOSシステムコールから情報を回復することであるということです...

Perl 5.8-8のperlportには、ターゲットのエンディアン性に関する次の推奨テストがあります。

さまざまなCPUが、整数と浮動小数点数をさまざまな順序(エンディアンと呼ばれる)と幅(現在最も一般的な32ビットと64ビット)で格納します。これは、プログラムがバイナリ形式で1つのCPUアーキテクチャから別のCPUアーキテクチャに番号を転送しようとするときに影響します。通常、ネットワーク接続を介して「ライブ」であるか、ディスクファイルやテープなどのセカンダリストレージに番号を保存します。

競合する保管注文は、数を完全に混乱させます。リトルエンディアンホスト(Intel、VAX)が0x1234567830541989610進数で)格納する場合、ビッグエンディアンホスト(Motorola、Sparc、PA)はそれを 0x78563412201891534610進数で)読み取ります。AlphaとMIPSは、次のいずれかになります。デジタル/コンパックが使用/リトルエンディアンモードで使用。SGI / Crayは、それらをビッグエンディアンモードで使用します。ネットワーク(ソケット)接続でこの問題を回避するには、packandunpack形式nN「ネットワーク」順序を使用します。これらはポータブルであることが保証されています。

perl 5.8.5以降では、>および<修飾子を使用して、ビッグエンディアンまたはリトルエンディアンのバイトオーダーを強制することもできます。これは、たとえば、符号付き整数または64ビット整数を格納する場合に役立ちます。

次のようなネイティブ形式でパックされたデータ構造を解凍することで、プラットフォームのエンディアンを調べることができます。

   print unpack("h*", pack("s2", 1, 2)), "\n";
   # '10002000' on e.g. Intel x86 or Alpha 21064 in little-endian mode
   # '00100020' on e.g. Motorola 68040

エンディアンアーキテクチャを区別する必要がある場合は、次のように設定された変数のいずれかを使用できます。

   $is_big_endian    = unpack("h*", pack("s", 1)) =~ /01/;
   $is_little_endian = unpack("h*", pack("s", 1)) =~ /^1/;

幅が異なると、エンディアンが等しいプラットフォーム間でも切り捨てが発生する可能性があります。幅が短いプラットフォームでは、数字の上部が失われます。生の2進数の転送または保存を回避する以外に、この問題に対する適切な解決策はありません。

これらの問題は2つの方法で回避できます。数値を生のバイナリではなく常にテキスト形式で転送して保存するか、Data::Dumper(Perl 5.005以降の標準ディストリビューションに含まれている)やStorable(perl 5.8以降に含まれている)などのモジュールの使用を検討してください。すべてのデータをテキストとして保持すると、問題が大幅に簡素化されます。

v2147483647v-stringは、 ( )までしか移植できませ0x7FFFFFFFん。これは、EBCDIC、より正確にはUTF-EBCDICが進む距離です。

unpack("h*",...)より頻繁に使用されているようですpack("h*",...)。私はそれがPerl5.12で 使用さreturn qq'unpack("F", pack("h*", "$hex"))';れていることに注意しましたDeparse.pmIO-Compresspack("*h",...)

さらに例が必要な場合は、Googleコード検索リストをご覧ください。ご覧pack|unpack("h*"...)のとおり、かなりまれであり、主にプラットフォームのエンディアンを決定することに関係しています...

于 2010-10-04T18:07:53.660 に答える
4

これは、エンディアンの異なるマシンにデータを転送したり、マシンからデータを読み取ったりするときに役立つと思います。一部のプロセスが、通常メモリ内でデータを表す方法でデータを受信することを期待している場合は、その方法でデータを送信することをお勧めします。

于 2010-10-04T17:16:57.283 に答える
2

この2つの違いは、ビッグエンディアンとリトルエンディアンのどちらのデータを使用しているかに関係しています。データのソースまたは宛先を制御できない場合があるため、パックするフラグHhフラグがオプションを提供します。同じ理由でそこにいますVN

于 2010-10-04T17:17:19.070 に答える