ASCII 문자열 및 엔디안니스
저와 함께 일하는 인턴이 컴퓨터 공학에서 본 엔디안니스 문제에 대한 시험을 보여주었습니다.ASCII 문자열 "My-Pizza"를 보여주는 질문이 있었는데, 학생은 그 문자열이 작은 엔디안 컴퓨터에서 메모리에 어떻게 표현되는지를 보여줘야 했다.물론 ASCII 문자열은 endian 문제에 영향을 받지 않기 때문에 이는 트릭 질문처럼 들립니다.
하지만 놀랍게도 이 인턴은 교수님이 현악기가 다음과 같이 표현될 것이라고 주장합니다.
P-yM azzi
이럴 리가 없다는 거 알아ASCII 문자열은 어떤 머신에서도 이와 같이 표시되지 않습니다.그런데 교수님이 이걸 고집하시는 것 같아요.그래서 작은 C 프로그램을 써서 인턴에게 교수님께 전해달라고 했어요.
#include <string.h>
#include <stdio.h>
int main()
{
const char* s = "My-Pizza";
size_t length = strlen(s);
for (const char* it = s; it < s + length; ++it) {
printf("%p : %c\n", it, *it);
}
}
이는 문자열이 메모리에 "My-Pizza"로 저장되어 있음을 명확하게 보여줍니다.하루 후 인턴이 저에게 연락하여 교수님이 현재 C가 문자열을 올바른 순서로 표시하기 위해 주소를 자동 변환하고 있다고 주장하고 있다고 합니다.
교수님이 미쳤다고 했는데 이건 분명히 잘못된 거예요다만, 여기서 자신의 온전성을 확인하기 위해서, 스택 오버 플로우에 투고하기로 했습니다.다른 사람이 제 말을 확인하게 할 수 있도록 하기 위해서입니다.
그래서 나는 묻는다: 바로 여기 있는 사람은 누구인가?
의심할 여지 없이, 당신이 옳아요.
ANSI C 표준 6.1.4는 문자열 리터럴이 리터럴의 문자를 "연결"하여 메모리에 저장되도록 지정합니다.
ANSI 표준 6.3.6은 포인터 값에 대한 덧셈의 효과도 규정한다.
적분형식을 포인터에 추가하거나 포인터에서 빼면 포인터 피연산자 유형이 결과에 포함됩니다.포인터 오퍼랜드가 배열 객체의 요소를 가리키고 배열이 충분히 클 경우, 결과는 결과 및 원본 배열 요소의 첨자 차이가 적분식과 동일하도록 원래 요소로부터의 오프셋 요소를 가리킵니다.
만약 이 사람의 아이디어가 맞다면, 정수를 배열 인덱스로 사용할 때 컴파일러는 정수 연산도 함께 해야 합니다.다른 많은 오류들도 상상에 맡기는 결과를 낳을 것이다.
(문자열 이니셜라이저와 달리) 'ABCD'와 같은 다중 바이트 문자 상수가 엔디안 순서로 저장되기 때문에 헷갈릴 수 있습니다.
사람들이 이것에 대해 혼란스러워 하는 많은 이유들이 있다.다른 사람들이 여기서 제안했듯이, 그는 int 값의 가독성을 위해 내용이 바이트 스왑된 디버거 창에서 그가 보는 것을 잘못 읽고 있을 수 있습니다.
교수님이 혼란스러워하고 있어요.'P-yM azi'와 같은 것을 보려면 메모리를 '4바이트 정수' 모드로 표시하고 동시에 상위 바이트에서 하위 바이트 모드로 각 정수의 "문자 해석"을 제공하는 메모리 검사 도구를 사용해야 합니다.
물론 이것은 문자열 자체와는 관계가 없습니다.그리고 끈 자체가 작은 기계에서 그렇게 표현된다고 말하는 것은 완전히 말도 안 되는 소리입니다.
엔디안니스에서는 멀티바이트 값 내의 바이트 순서를 정의합니다.문자열은 단일 바이트 값의 배열입니다.따라서 각 값(문자열 내의 문자)은 리틀 엔디안과 빅 엔디안 아키텍처 모두에서 동일하며 엔디안은 구조 내의 값 순서에 영향을 주지 않습니다.
한 글자당 8비트를 사용하는 시스템이라면 교수님은 틀렸습니다.
저는 보통 16비트 문자를 사용하는 임베디드 시스템으로 작업하고 있습니다.각 단어는 little-endian입니다.이러한 시스템에서는 문자열 "My-Pizza"가 "yMP-ziaz"로 저장됩니다.
단, 문자당8비트 시스템인 한 문자열은 상위 아키텍처의 엔디안니스와는 무관하게 항상 "My-Pizza"로 저장됩니다.
문자열이 전달되었는지 모르는 함수로 인쇄를 수행함으로써 컴파일러가 이러한 "매직" 변환을 하지 않는다는 것을 쉽게 증명할 수 있습니다.
int foo(const void *mem, int n)
{
const char *cptr, *end;
for (cptr = mem, end = cptr + n; cptr < end; cptr++)
printf("%p : %c\n", cptr, *cptr);
}
int main()
{
const char* s = "My-Pizza";
foo(s, strlen(s));
foo(s + 1, strlen(s) - 1);
}
로 컴파일할 수도 있습니다.gcc -S
마법의 부재를 결정짓는 거죠
하지만 놀랍게도 이 인턴은 교수님이 현악기가 다음과 같이 표현될 것이라고 주장합니다.
P-yM 아지
뭐로 표현될까요?사용자에게 32비트 정수 덤프로 표시됩니까?컴퓨터 메모리에 P-yM azzi로 표시/배치되는가?
만약 교수가 "마이피자"가 컴퓨터 메모리에 "P-yM azi"로 표현/배치될 것이라고 말했다면, 컴퓨터가 작은 엔디언 아키텍처이기 때문에 누군가 디버거 사용법을 교수에게 가르쳐야 합니다!나는 교수님의 모든 혼란이 거기서 비롯되었다고 생각한다.나는 교수가 코더가 아니라는 것을 암시한다(나는 그 교수를 무시하지 않는다). 나는 그가 엔디안니스에 대해 배운 것을 코드로 증명할 방법이 없다고 생각한다.
아마 교수님은 일주일 전에 엔디안니스에 관한 것을 배웠을지도 모릅니다.그리고 디버거를 잘못 사용했을 뿐이죠.컴퓨터에 대한 그의 새로운 통찰력에 금방 기뻐하고 나서 학생들에게 즉시 설교합니다.
교수가 기계의 엔디안성이 기억 속에서 아스키 문자열이 어떻게 표현될지와 관련이 있다고 말했다면, 그는 자신의 행동을 바로잡아야 한다.
교수가 기계에서 정수가 어떻게 다르게 표현/배치되는지에 대한 예를 대신 제시한다면, 그의 학생들은 그가 가르치는 모든 것에 대해 이해할 수 있을 것이다.
교수님이 엔디안/NUXI 문제에 대해 유추해서 논점을 만들려 하셨다고 생각합니다만, 실제의 현에 적용하면 당신이 옳습니다.그가 학생들에게 어떤 문제에 대해 어떻게 생각하는지를 가르치려 했다는 사실에서 탈선하지 않도록 하세요.
관심이 있을 수도 있지만, 빅 엔디안 머신에서 리틀 엔디안 아키텍처를 에뮬레이트하거나 그 반대일 수도 있습니다.. 코드 방출은 최소 유효 비트와 마법에 의해 자동으로 교란됩니다.char*
32일 00 <-> 11일 01 <-> 10일
'아까운'이라는 를 쓰면0x01020304
번째 이 할당으로 바이트인 "첫 바이트를 수 .0x04
C의 실장은 하드웨어가 빅 엔디안인데도 리틀 엔디안입니다.
짧은 액세스에도 비슷한 트릭이 필요합니다.얼라인먼트되지 않은 액세스(지원되는 경우)는 인접 바이트를 참조하지 않을 수 있습니다.또한 단어보다 큰 유형에는 네이티브 저장소를 사용할 수 없습니다. 한 번에 한 바이트씩 다시 읽으면 단어 스왑으로 표시되기 때문입니다.
단, little-endian 머신이 항상 이렇게 하는 것은 아닙니다.이것은 매우 전문적인 요건이며, 네이티브 ABI를 사용할 수 없게 됩니다.교수님은 실제 숫자를 "사실상" 빅엔디안이라고 생각하고 리틀엔디안 건축이 실제로 무엇인지 그리고/또는 그 기억이 어떻게 표현되고 있는지에 대해 깊이 혼란스러워하는 것처럼 들립니다.
'이 됩니다.P-yM azzi
32비트 l-e 머신에서는 "표현된" 경우에만 "주소가 증가하는 순서대로 표현된 단어를 읽지만 각 단어의 바이트는 big-endian"으로 인쇄합니다.다른 사람들이 말했듯이, 이것은 일부 디버거 메모리 뷰가 할 수 있는 일이기 때문에 실제로 메모리 내용을 표현한 것입니다.단, 각 바이트를 나타내는 경우에는 각 단어를 다중 문자 리터럴로 표시하는 것이 아니라 단어를 저장하든 b-e든 l-e든 주소의 증가 순서로 나열하는 것이 일반적입니다.물론 포인터를 만지작거리는 일은 없고, 만약 교수님이 선택한 변론을 통해 그가 어떤 것이 있다고 생각하도록 했다면, 그것은 그를 오도한 것이다.
또, (오랜만에 가지고 놀기 때문에 틀릴지도 모릅니다)그는 pascol을 생각할지도 모릅니다.이 pascol은 문자열이 "packed array"로 표현되어 있습니다.IIRC는 4바이트 정수로 채워져 있는 문자입니다.
AFIK, endianness는 큰 값을 작은 값으로 나누고 싶을 때만 의미가 있습니다.그래서 C스타일의 스트링은 영향을 받지 않는다고 생각합니다.왜냐하면 그들은 결국 단지 글자 배열이기 때문이다.1바이트만 읽을 때 왼쪽에서 읽든 오른쪽에서 읽든 상관없습니다.
교수의 생각을 읽는 것은 어렵지만 컴파일러는 바이트를 BE와 LE 시스템 양쪽의 인접한 증가 주소에 저장하는 것 외에는 아무것도 하지 않습니다.단, Word 사이즈에 관계없이 메모리를 Word 사이즈로 표시하는 것은 일반적이며, 1,000은 Word 사이즈로 씁니다.000, 1이 아닙니다.
$ cat > /tmp/pizza
My-Pizza^D
$ od -X /tmp/pizza
0000000 502d794d 617a7a69
0000010
$
기록의 경우 y == 79, M == 4d입니다.
나는 이것을 우연히 발견했고 그것을 해명할 필요성을 느꼈다.도 이 에 대해 하지 않은 것 .byte
및word
또는 그 대처법을 참조해 주세요.바이트는 8비트입니다.단어는 바이트 집합입니다.
시스템이 다음과 같은 경우:
- 바이트 주소 지정 가능
- 4바이트(32비트) 워드를 사용하여
- 단어 정렬
- 메모리는 "물리적으로" 표시된다(덤프되지 않고 바이트 단위로 표시됨)
그렇다면 정말 교수님이 옳을 것이다.그가 이것을 나타내지 않는 것은 그가 무슨 말을 하고 있는지 정확히 알지 못한다는 것을 증명하지만, 그는 기본적인 개념을 이해했다.
단어 내 바이트 순서: (a) 빅 엔디안, (b) 리틀 엔디안
단어 내 문자 및 정수 데이터: (a) 빅 엔디안, (b) 리틀 엔디안
레퍼런스
언급URL : https://stackoverflow.com/questions/1568057/ascii-strings-and-endianness
'programing' 카테고리의 다른 글
Intelij IDEA Java 클래스가 저장 시 자동으로 컴파일되지 않음 (0) | 2022.08.10 |
---|---|
점프 테이블이 뭐죠? (0) | 2022.08.10 |
Vue-test-utils 래퍼가 정의되지 않았습니다. (0) | 2022.08.10 |
코딩 규칙 - 명명 규칙 (0) | 2022.08.10 |
반환을 위해 개체를 일반 유형으로 캐스팅 (0) | 2022.08.10 |