lsとhexdumpが私のファイルサイズに同意しないのはなぜですか?

lsとhexdumpが私のファイルサイズに同意しないのはなぜですか?

テスト目的で(SSHクライアントからUTF-8出力をテストするために)ファイルを(vimで)作成しました。しかし、このファイルに奇妙なことが起こります。

ファイルにどのバイトがあるかを知りたかったので、次のようにしましたhexdump

username@computername:~$ hexdump -x intl.txt
0000000    9ecf    000a
0000003

まあ、そこには4バイトがあります。どのように00と0aがそこに入ってきたのか分からないが、とにかく言葉です。しかし、奇妙なことは次のとおりです。

username@computername:~$ ls -al intl.txt
-rw-rw-r-- 1 username username 3 Mar 26 15:14 intl.txt

待って、3バイトですか?ここで何が起こっているのでしょうか?

これは十分に奇妙ではないように、hexdump -C非常に異なる結果を提供します。

username@computername:~$ hexdump -C intl.txt
00000000  cf 9e 0a                                          |...|
00000003

Vimもこのファイルについて少し混乱しています。起動すると、ステータス行に次のように表示されます。

"intl.txt" 1L, 3C

ただし、一番上には次の内容が表示されます(使用set list)。

Ϟ$
~
~
~
~

したがって、3つの文字があると思いますが、1つだけを印刷します。 koppaとその下に空白行が印刷されているとわかります...

答え1

他の人が指摘したように、これはファイルがhexdump -x2バイトの単語を含むと見なされるためです。存在するリトルエンディアンシステム(ほとんどのデスクトップがそうです)。これは、表示される前にバイトが交換されることを意味します。これは、バイト値がペアで印刷され、これらのバイトの順序が変わることを意味します。バイト数が奇数なので、hexdumpゼロを追加して最終ペアを作成します。次に0を0a。これは文書化された動作hexdumpなので、嘘をつくのではありません!

より良いコマンドは、hexdump -Cファイルに表示される順序でバイトを表示する形式化された出力を取得することです。また、これは0aファイルを作成した人が自動的に追加した可能性がある新しい行です(vimデフォルトではこれを行います)。たとえば、echoこれを行わないように指示しないと、常に新しい行が追加されます。存在するbash

echo -e '\xcf\x9e' | hexdump -C

同じ結果が得られますが、改行を抑えることで-n期待した結果が得られます。

echo -ne '\xcf\x9e' | hexdump -C

改行の追加を停止するには、次の手順を実行しますvim

:set noeol
:set binary

答え2

hexdump -x値を2バイト整数で表示します。以前のリトルエンディアン方式システムは、各バイトペアを置き換えられた順序で表示し、それをダブルバイト数量として処理し、上位(2番目)バイトが最初に、次に下位(最初)バイトが表示されます。

ご覧のとおり、使用するとhexdump -C実際のバイトが表示されます。ファイルの実際の内容は2バイト0xCF 0x9Eで、その後に改行文字0x0Aが続きます。 3バイト(2文字)があると正確にお知らせしますVimls最初の2バイトには、UTF-8でエンコードされたUnicode文字が含まれています。

上記のコメントにもっと興味深い情報があります。

答え3

バイトの順序を理解できない場合は、別の例をご覧ください。

#include <stdio.h>
#include <inttypes.h>
#include <unistd.h>

int main (void) {
    uint16_t x = 1;
    write(1, &x, 2);
    x = 2;
    write(1, &x, 2);
    return 0;
}  

16ビット値1と2の2つを出力するCコードです。値について考えると、これをビッグエンディアンと考えているので、ここでパディング(これらの16ビット値を生成するため)は、0のバイトと値1(または2)のバイトがあることを意味します。しかし、システムがあるのでリトルエンディアンここで、これら2つの個別の16ビット(2バイト)単位を考慮すると、実際に書き込まれた4バイトは1、0、2、0です。

そのエントリ()をコンパイルしgcc whatever.cてファイル(./a.out > dword)にリダイレクトすると、hexdump -Cバイトの物理的な順序が表示されます。

> hexdump -C dword
00000000  01 00 02 00  |....|
00000004

ただし、この場合、hexdump -x2つの正しい16ビット値を示すためにバイトを交換するので、意味の点でより正確な説明が提供されます。

> hexdump -x dword
0000000    0001    0002                                                
0000004

この4バイトが(リトルエンディアン)32ビット整数として解釈される場合:

> hexdump -e '"%d\n"' dword
131073

これは、32ビットの2進値を10進値に変換するためです。

00000001 00000000 00000010 00000000

としてビッグエンディアン方式値、つまり 2^9(512) + 2^24(16777216) です。これは、私たちがビッグエンディアンの順序で「考える」と言う意味です。バイナリを書くと、ビッグエンディアン表記を使用します。ビット順(1バイト00000010== 2)したがって、数値が1バイトより長い場合はビッグエンディアンを使用します。バイト順(2バイト0000000000000010== 2)。

ただし、システムはリトルエンディアン(1)なので、このバイトを2進数で書き込んで32位置にパディングする(読みやすくするために8ビットごとに同じスペースを使用する)、次のようになります。

00000000 00000010 00000000 00000001

10 進表記法では 2^17(131072) + 2^0(1) です。実際にプログラムの本文を次のように置き換えると:

int main (void) {
    uint32_t x = 131073;
    write(1, &x, 4);
    return 0;
}  

あなたが得るファイルにコンパイルして書くまったく同じ出力hexdumpファイルにはまったく同じ内容が含まれているため、以前と同じです。

1.バイト順序について話すとき、実際には常にバイト順序を意味することに注意してください。最小の単位は実際にはバイトなので、ビットの順序は重要ではありません。

関連情報