테스트 목적으로 (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 -x
파일이 2바이트 단어를 포함하는 것으로 간주되기 때문입니다. 존재하다리틀 엔디안시스템(거의 모든 데스크탑이 그렇습니다). 이는 표시되기 전에 바이트가 교환된다는 것을 의미합니다. 이는 바이트 값이 쌍으로 인쇄되고 이러한 바이트의 순서가 바뀌는 것을 의미합니다. 바이트 수가 홀수이므로 hexdump
0을 추가하여 최종 쌍을 만드세요. 그런 다음 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바이트 정수로 표시합니다. 이전의리틀 엔디안 방식시스템은 각 바이트 쌍을 교체된 순서로 표시하여 이를 더블 바이트 수량으로 처리하며 상위(두 번째) 바이트가 먼저, 그 다음 하위(첫 번째) 바이트가 표시됩니다.
보시다시피 를 사용하면 hexdump -C
실제 바이트가 표시됩니다. 파일의 실제 내용은 2바이트 0xCF 0x9E이고 그 뒤에 개행 문자 0x0A가 옵니다. 3바이트(2자)가 있다고 정확하게 알려줍니다 Vim
. ls
처음 2바이트에는 UTF-8로 인코딩된 유니코드 문자가 포함되어 있습니다.
위의 댓글에 더 흥미로운 정보가 있습니다.
답변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)의 바이트가 있음을 의미합니다. 그러나 시스템이 있기 때문에리틀 엔디안여기서 이 두 개의 개별 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 -x
올바른 두 개의 16비트 값을 표시하기 위해 바이트를 교환하므로 의미 측면에서 더 정확한 설명이 제공됩니다.
> hexdump -x dword
0000000 0001 0002
0000004
이 4바이트가 (리틀 엔디안) 32비트 정수로 해석되는 경우:
> hexdump -e '"%d\n"' dword
131073
다음 32비트 이진수 값을 십진수 값으로 변환하기 때문입니다.
00000001 00000000 00000010 00000000
로서빅엔디안 방식값, 즉 2^9(512) + 2^24(16777216)입니다. 이것이 바로 우리가 빅 엔디안 순서로 "생각한다"고 말하는 의미입니다. 이진수를 쓰면 빅 엔디안 표기법을 사용합니다.비트 순서(1바이트 00000010
== 2) 따라서 숫자가 1바이트보다 길면 빅 엔디안을 사용합니다.바이트 순서(2바이트 0000000000000010
== 2).
그러나 시스템은 리틀 엔디안 (1) 이므로 이 바이트를 이진수로 쓰고 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. 바이트 순서에 관해 이야기할 때 실제로는 항상 바이트 순서를 의미한다는 점에 유의하세요. 가장 작은 단위는 실제로 바이트이므로 비트 순서는 중요하지 않습니다.