리틀 엔디안 형식의 장점은 무엇입니까?


140

인텔 프로세서 (및 다른 프로세서)는 스토리지에 리틀 엔디안 형식을 사용합니다.

나는 왜 누군가가 바이트를 역순으로 저장하고 싶어하는지 궁금합니다. 이 형식은 빅 엔디안 형식보다 장점이 있습니까?


1
6502는 초기 (첫 번째?) 파이프 라인 프로세서였습니다. 파이프 라인으로 인해 성능 관련 문제에 대해 리틀 엔디안이라는 주장을 기억하는 것 같습니다.하지만 그 문제가 무엇인지 알 수 없습니다. 어떤 제안?
Steve314

1
@ Steve314 : 내 대답은 리틀 엔디안이 파이프 라인 CPU의 성능을 어떻게 향상시키는 지 설명합니다. programmers.stackexchange.com/q/95854/27874
Martin Vilcans

3
리틀 엔디안, 빅 엔디안-둘 중 하나를 선택해야합니다. 도로의 왼쪽이나 오른쪽에서 운전하는 것과 같습니다.

3
6502 또는 Z80과 같은 "오래된 학교"아키텍처를 위해 ASM으로 코드를 작성하는 것이 좋습니다. 왜 이들이 리틀 엔디안을 사용하는지 즉시 알 수 있습니다. 빅 엔디안을 사용하는 아키텍처에는 명령어 세트에 특정 특성이있어 해당 형식을 선호합니다. 자의적인 결정은 아닙니다!
Stefan Paul Noack이

2
각 바이트 순서 시스템에는 장점이 있습니다. Little-endian 시스템을 사용하면 다른 시스템을 읽지 않고도 최저 바이트를 먼저 읽을 수 있습니다. 숫자가 홀수인지 짝수인지 (마지막 비트가 0 임) 매우 쉽게 확인할 수 있습니다. Big-endian 시스템은 인간이 데이터 (왼쪽에서 오른쪽으로)에 대해 생각하는 것과 같은 방식으로 메모리에 데이터를 저장하므로 저수준 디버깅이 쉬워집니다.
Koray Tugay

답변:


198

어느 쪽이든 논쟁이 있지만 한 가지 요점은 리틀 엔디안 시스템에서 32, 16 또는 8 비트 폭으로 취한 메모리의 주어진 값의 주소가 동일하다는 것입니다.

즉, 메모리에 2 바이트 값이있는 경우 :

0x00f0   16
0x00f1    0

'16'을 16 비트 값 (대부분의 32 비트 시스템에서 c '짧음') 또는 8 비트 값 (일반적으로 c 'char')으로 사용하면 가져 오는 주소가 아니라 사용하는 가져 오기 명령 만 변경됩니다. 에서.

빅 엔디안 시스템에서 위의 내용은 다음과 같습니다.

0x00f0    0
0x00f1   16

포인터를 증가시킨 다음 새 값에서 더 좁은 페치 조작을 수행해야합니다.

간단히 말해, '작은 엔디안 시스템에서는 캐스트가 작동하지 않습니다.'


3
물론 읽지 않은 상위 ​​바이트는 합리적으로 무시할 수 있다고 가정합니다 (예를 들어 어쨌든 0임을 알고 있습니다).
Steve314

10
@ Steve314 : 2의 보완 시스템 (예 : 대다수의 시스템)에서 32 비트에서 16 비트로 (예를 들어) C 다운 캐스팅하는 경우 바이트를 무시 할 필요가 없습니다. 그들의 가치에 관계없이 나는 그것들을 무시하고 C 표준 및 프로그래머의 기대에 부응 할 수 있습니다.

9
@Stritzinger-우리는 컴파일러가 생성 한 어셈블리 / 머신 코드에 대해 이야기하고 있습니다. 컴파일 할 고급 언어 코드는 이식성이 뛰어납니다. 모든 아키텍처에서와 같이 다른 아키텍처에서 다른 작업으로 컴파일하기 만합니다.
jimwise

7
빅 엔디안 아키텍처에서는 포인터가 시작이 아니라 끝을 가리킬 수 있으며, 언급 한 것과 정확히 같은 이점을 가질 수있는 것의 끝을 가리킬 수 있기 때문에 저는이 주장을 사지 않습니다.
dan_waterworth

4
@dan_waterworth는 확실하지 않습니다. 예를 들어 C의 포인터 산술 규칙과 동일한 포인터의 캐스트를 늘리거나 줄일 때 발생하는 일을 명심하십시오. 복잡성을 이동할 수는 있지만 제거 할 수는 없습니다.
jimwise

45

나는 왜 누군가가 바이트를 역순으로 저장하고 싶어하는지 궁금합니다.

빅 엔디안과 리틀 엔디안은 인간의 관점에서 볼 때 "정상 질서"와 "역순"일뿐입니다.

  1. 화면이나 종이에서 값을 읽습니다.
  2. 낮은 메모리 주소는 왼쪽에, 높은 메모리 주소는 오른쪽에 배치합니다.
  3. 왼쪽에 높은 순서의 nybble 또는 왼쪽에 가장 중요한 비트가있는 binary를 16 진수로 작성합니다.
  4. 왼쪽에서 오른쪽으로 읽습니다.

그것들은 CPU에 전혀 중요하지 않은 모든 인간 관습입니다. # 1과 # 2를 유지하고 # 3을 뒤집 으면 리틀 엔디안은 오른쪽에서 왼쪽으로 쓰는 아랍어 나 히브리어를 읽는 사람들에게 "완벽하게 자연스러워"보일 것입니다.

그리고 빅 엔디안을 부 자연스럽게 보이게하는 다른 인간 협약이 있습니다 ...

  • "더 높은"(가장 중요한) 바이트는 "더 높은"메모리 주소에 있어야합니다.

필자가 68K와 PowerPC를 주로 프로그래밍 할 때 빅 엔디안은 "올 바르고", 리틀 엔디안은 "잘못됨"으로 간주했다. 그러나 더 많은 ARM 및 인텔 작업을 수행 한 이후로 리틀 엔디안에 익숙해졌습니다. 정말 중요하지 않습니다.


30
숫자는 사실 아랍어와 히브리어로 [가장 큰 자리]에서 [가장 큰 자리]로 오른쪽에 쓰여집니다.
Random832

5
그렇다면 왜 바이트 내의 비트가 "빅 엔디안"형식으로 저장됩니까? 왜 일관성이 없습니까?
tskuzzy

11
비트 0은 일반적으로 가장 중요하지 않으며 비트 7은 가장 중요합니다. 또한 비트는 개별적으로 주소를 지정할 수 없으므로 일반적으로 바이트 내의 비트에 순서를 지정할 수 없습니다. 물론, 그들은 주어진 통신 프로토콜 또는 스토리지 미디어에서 물리적 순서를 가질 수 있지만, 낮은 수준의 프로토콜 또는 하드웨어 수준에서 작업하지 않는 한이 순서에 대해 걱정할 필요가 없습니다.
스튜어트

3
BlueRaja : 종이에 글을 쓰는 관례에 의해서만 가능합니다. 이것은 CPU 아키텍처와 공통점이 없습니다. 바이트를 7-0 MSB-LSB 대신 0-7 LSB-MSB로 쓸 수 있으며 알고리즘 관점에서 아무것도 변하지 않습니다.
SF.

2
@SF : "팝업, 짧은 밀어 짧은 아무것도하지만 "어쨌든 당신에게 깜짝 선물을 얻을 것이다. 당신이 팝업하거나 그 반대의 경우도 마찬가지 ... 86 (32 비트) 결코 바이트를 밀어 스택을 손상하지 않더라도, 예를 들어, 정말 정말 스택이-DWORD 정렬 및 밀거나 원인이 무엇이든 터지는되고 싶어 4의 배수가 아닌 스택 포인터는 정렬 문제를 일으킬 수 있습니다. 그리고 그렇지 않은 경우에도 물건은 한 번에 전체 단어 / dword / qword / 등을 밀어 넣었습니다. 따라서 낮은 바이트는 여전히 팝 할 때 얻는 첫 번째 바이트입니다.
cHao

41

좋아, 여기에 나에게 설명했던 이유가 있습니다 : 덧셈과 뺄셈

멀티 바이트 숫자를 더하거나 빼는 경우 최하위 바이트로 시작해야합니다. 예를 들어 두 개의 16 비트 숫자를 추가하는 경우 최하위 바이트에서 최상위 바이트로의 캐리가있을 수 있으므로 캐리가 있는지 확인하려면 최하위 바이트로 시작해야합니다. 이것은 장기 덧셈을 할 때 가장 오른쪽 숫자로 시작하는 것과 같은 이유입니다. 왼쪽부터 시작할 수 없습니다.

메모리에서 바이트를 순차적으로 페치하는 8 비트 시스템을 고려하십시오. 최하위 바이트를 먼저 페치하면 최상위 바이트가 메모리에서 페치되는 동안 추가 시작할 수 있습니다 . 이러한 병렬성은 시스템과 같은 리틀 엔디안에서 성능이 더 좋은 이유입니다. 두 바이트가 메모리에서 페치 될 때까지 기다려야하거나 역순으로 페치하면 시간이 더 오래 걸립니다.

이것은 오래된 8 비트 시스템에 있습니다. 현대의 CPU에서는 바이트 순서가 차이를 의심하고 역사적인 이유로 만 리틀 엔디안을 사용합니다.


3
아-그래서 큰 정수에 리틀 엔디안 청크 순서를 사용하는 것과 거의 같은 이유입니다. 나는 그것을 해결해야했습니다. 사람들은 이제 사이버네틱스를 연구해야합니다. 제 뇌는 이미 교체 부품과 급격한 업그레이드가 절실히 필요하기 때문에 영원히 기다릴 수 없습니다!
Steve314

2
6502는 하드웨어에서 16 비트 수학을 많이하지 않았다는 생각은 결국 8 비트 프로세서였습니다. 그러나 16 비트 기본 주소를 기준으로 8 비트 부호 오프셋을 사용하여 주소 상대 할.
Steve314

2
이 아이디어는 여전히 Steve Level이 말한 것처럼 다중 정밀도 정수 산술에 중요하지만 단어 수준에서는 중요합니다. 이제 대부분의 작업은 프로세서의 엔디안 (endian)에 의해 직접적인 영향을받지 않습니다. GMP에 의해 수행되는 것처럼 가장 중요한 단어를 빅 엔디안 시스템에 먼저 저장할 수 있습니다. 리틀 엔디안 프로세서는 리틀 엔디안 시스템에서만 해당 숫자의 바이트 순서가 정확하기 때문에 한 번에 한 바이트 씩 읽음으로써 쉽게 수행 할 수있는 몇 가지 작업 (예 : 일부 문자열 변환)에 이점이 있습니다.
vinc17

리틀 엔디안 프로세서는 16 비트 메모리 버스를 사용하는 일부 32 비트 ARM 프로세서 또는 8 비트 데이터 버스를 사용하는 8088과 같이 메모리 대역폭이 제한되어있는 경우 이점이 있습니다. 추가 / 하위 / mul ... 더 높은 반쪽을 기다리는 동안 그것으로
phuclv

13

8 비트 프로세서를 사용하면 확실히 더 효율적 이었으므로 다른 코드 나 추가 값을 버퍼링하지 않고도 8 비트 또는 16 비트 작업을 수행 할 수 있습니다.

한 번에 바이트를 처리하는 경우 일부 추가 작업에 더 좋습니다.

그러나 빅 엔디안이 더 자연스러운 이유는 없습니다. 영어에서는 13 (little endian)과 23 (big endian)을 사용합니다.


1
Big-endian은 바이트를 다시 정렬 할 필요가 없기 때문에 실제로 사람에게 더 쉽습니다. 예를 들어, PC에서는 BE 시스템에있는 0x12345678것처럼 저장됩니다 (바이트 0은 왼쪽에, 바이트 3은 오른쪽에 있음). 숫자가 클수록 (비트 단위) 스왑이 더 많이 필요하다는 점에 유의하십시오. WORD는 한 번의 스왑이 필요합니다. DWORD, 2 패스 (3 개의 총 스왑); QWORD 세 번 (총 7 번) 등. 즉 스왑입니다. 또 다른 옵션은 그들에게 모두 전달을 읽고 이전 버전 (각 바이트의 전달을 읽는하지만 뒤쪽으로 전체 #를 스캔). 78 56 34 1212 34 56 78(bits/8)-1
Synetech

100과 13은 중간 엔디안이거나 "13"이 본질적으로 하나의 10 진수가 아닌 빅 엔디안입니다. 우리가 숫자를 맞추는 때, 우리는 숫자에 사용하는 일정한 기본 규칙에서 약간의 편차가있다, 그러나 당신이 그 특별한 경우를 제거하면 나머지는 빅 엔디안이다 - 수백만 전에 수천, 수천 이전 등 수백
Steve314

@ Synetech- 다행스럽게도 컴퓨터는 사람이 읽는 방식에 신경 쓸 필요가 없습니다. 즉 NAND 플래시 '하다며 때문에 더 낫다고 주장처럼
마틴 베켓을

1
@ Steve314, 숫자의 철자가 중요하지 않은 것은 프로그래밍 할 때 사용하는 수치입니다. 마틴, 컴퓨터는 사람이 숫자를 읽는 방식에 신경 쓸 필요가 없지만 사람이 쉽게 읽을 수 있다면 프로그래밍 (또는 다른 관련 작업)이 쉬워지고 일부 결함과 버그를 줄이거 나 피할 수 있습니다.
Synetech

@ steve314 그리고 덴마크어에서 "95"는 "fem halvfems"(5, 4, 2, 2, 20)로 발음됩니다.
Vatine

7

일본 날짜 규칙은 "big endian"-yyyy / mm / dd입니다. 이는 알고리즘을 정렬하는 데 편리하며 일반적인 첫 번째 문자는 가장 중요한 규칙과 간단한 문자열 비교를 사용할 수 있습니다.

가장 중요한 필드 우선 레코드에 저장된 빅 엔디안 숫자에도 비슷한 내용이 적용됩니다. 필드 내 바이트의 중요도는 레코드 내 필드의 중요성과 일치하므로 a memcmp를 사용하여 레코드를 비교할 수 있지만 두 개의 Longword, 4 워드 또는 8 개의 개별 바이트를 비교하든 상관 없습니다.

필드의 중요성 순서를 바꾸면 동일한 이점을 얻을 수 있지만 빅 엔디안이 아닌 리틀 엔디안 번호에 해당합니다.

물론 이것은 실질적인 중요성이 거의 없습니다. 플랫폼이 빅 엔디안이든 리틀 엔디안이든 관계없이 필요한 경우이 트릭을 악용 할 레코드 필드를 주문할 수 있습니다. 이식 가능한 코드 를 작성해야하는 경우에는 고통 입니다.

고전적인 호소에 대한 링크를 포함시킬 수도 있습니다 ...

http://tools.ietf.org/rfcmarkup?url=ftp://ftp.rfc-editor.org/in-notes/ien/ien137.txt

편집하다

여분의 생각. 한 번 큰 정수 라이브러리를 작성했으며 (가능한 경우) 32 비트 너비 청크는 플랫폼이 해당 청크의 비트를 어떻게 정렬하는지에 관계없이 리틀 엔디안 순서로 저장됩니다. 그 이유는 ...

  1. 많은 알고리즘이 자연스럽게 최소한의 끝에서 작동하기 시작하고 그 끝이 일치되기를 원합니다. 예를 들어, 캐리는 점점 더 많은 유효 숫자로 전파되므로 최하위에서 시작하는 것이 좋습니다.

  2. 값을 늘리거나 줄이면 청크를 추가 / 제거한다는 의미이므로 청크를 위 / 아래로 이동할 필요가 없습니다. 메모리 재 할당으로 인해 여전히 복사가 필요할 수 있지만 자주는 아닙니다.

물론 이것은 프로세서와 밀접한 관련이 없습니다. CPU가 하드웨어 큰 정수 지원으로 만들어 질 때까지는 순수한 라이브러리입니다.


7

왜 이것이 이루어질 수 있는지에 대한 아무도 대답하지 않았습니다. 결과에 관한 많은 것들.

주어진 클럭 사이클에서 메모리에서 단일 바이트를로드 할 수있는 8 비트 프로세서를 고려하십시오.

이제 16 비트 값을로드하려는 16 비트 레지스터 (예 : 프로그램 카운터)에 16 비트 값을로드하려면 간단한 방법은 다음과 같습니다.

  • 페치 위치에서 바이트를로드
  • 바이트를 왼쪽으로 8 자리 이동
  • 메모리 페치 위치를 1 씩 증가
  • 다음 바이트를로드합니다 (레지스터의 하위 부분으로)

결과 : 페치 위치 만 늘리고 더 넓은 레지스터의 하위 부분에만로드하면 왼쪽으로 만 이동할 수 있습니다. (물론 오른쪽 이동은 다른 작업에 도움이되므로 약간의 부수적 인 쇼입니다.)

그 결과 16 비트 (더블 바이트) 항목이 대부분 순서대로 저장됩니다. 즉, 주소가 작을수록 가장 큰 바이트-큰 엔디안이 있습니다.

리틀 엔디안을 사용하여로드하려고하면 와이드 레지스터의 아래쪽에 바이트를로드 한 다음 스테이징 영역에 다음 바이트를로드하고 시프트 한 다음 더 넓은 레지스터의 상단에 팝해야합니다 . 또는 상위 또는 하위 바이트에 선택적으로로드 할 수 있도록보다 복잡한 게이팅 배열을 사용하십시오.

리틀 엔디안을 시도한 결과 더 많은 실리콘 (스위치 및 게이트)이 필요하거나 더 많은 작업이 필요합니다.

다시 말해, 예전에는 돈을 벌기 위해 대부분의 성능과 가장 작은 실리콘 영역에서 더 많은 돈을 벌었습니다.

요즘은 파이프 라인 채우기 등이 고려 사항과 거의 관련이없는,하지만 일이 있습니다 아직 큰 문제가 약간합니다.

S / W를 작성할 때 리틀 엔디 언 어드레싱을 사용하면 인생이 더 쉬워집니다.

(빅 엔디안 프로세서는 비트 -에 - 바이트의 관점에서 바이트 순서와 리틀 엔디안의 측면에서 큰 엔디안 경향이있다. 그러나 일부 프로세서 이상이며, 바이트 순서뿐만 아니라 주문 빅 엔디안 비트를 사용합니다.이 생활하게 매우를 메모리 매핑 주변 장치를 추가하는 하드웨어 디자이너에게는 흥미가 있지만 프로그래머에게는 다른 결과는 없습니다.)


3

Jimwise는 좋은 지적을했습니다. 리틀 엔디안에는 다음과 같은 문제가 있습니다.

byte data[4];
int num=0;
for(i=0;i<4;i++)
    num += data[i]<<i*8; 

OR 

num = *(int*)&data; //is interpreted as

mov dword data, num ;or something similar it has been some time

메모리에서 스왑 된 위치의 명백한 단점에 영향을받지 않는 프로그래머에게는 더 직설적입니다. 나는 개인적으로 빅 엔디안이 자연스러워하는 것에 반한다고 생각합니다. :). 12는 21로 저장하고 작성해야합니다. :)


1
이것은 CPU 고유의 형식으로 작업하는 것이 더 빠르고 쉽다는 것을 증명합니다. 더 나은지에 대해서는 아무 말도하지 않습니다. 빅 엔디안도 마찬가지 입니다. 빅 엔디안 CPU에 for(i=0; i<4; i++) { num += data[i] << (24 - i * 8); }해당합니다 move.l data, num.
Martin Vilcans

@martin : 한 적은 뺄셈 내 책에 더
인 Cem Kalyoncu

어쨌든 컴파일러가 루프를 풀기 때문에 실제로 중요하지 않습니다. 어쨌든 많은 CPU에는이 문제를 처리하기위한 바이트 스와핑 명령이 있습니다.
Martin Vilcans

빅 엔디안에서 bcoz에 동의하지 않습니다. {num << = 8; 숫자 | = 데이터 [i]; } 적어도 이것은 mul을 사용하여 왼쪽 쉬프트 카운트를 계산할 필요가 없습니다
Hayri Uğur Koltuk

@ali : 코드는 내가 작성한 정확한 작업을 수행하고 빅 엔디안에서는 작동하지 않습니다.
Cem Kalyoncu

1

나는 왜 누군가가 바이트를 역순으로 저장하고 싶어하는지 궁금합니다.

십진수는 빅 엔디안으로 작성됩니다. 또한 영어로 작성하는 방법 가장 중요한 숫자로 시작하고 다음으로 가장 중요한 숫자부터 가장 덜 중요한 숫자로 시작하십시오. 예 :

1234

천, 이백 삼십 사입니다.

이것은 빅 엔디안이 때때로 자연 질서라고 불리는 방식입니다.

리틀 엔디안에서이 숫자는 1, 2, 3, 3, 4 천입니다.

그러나 덧셈 또는 뺄셈과 같은 산술을 수행 할 때는 끝에서 시작합니다.

  1234
+ 0567
  ====

4와 7로 시작하여 가장 낮은 숫자를 쓰고 캐리를 기억하십시오. 그런 다음 3과 6 등을 더합니다. 더하기, 빼기 또는 비교를 위해 이미 메모리를 순서대로 읽는 논리가 있고 숫자가 반대로되어 있으면 구현하는 것이 더 간단합니다.

이러한 방식으로 빅 엔디안을 지원하려면 메모리를 반대로 읽는 논리가 필요하거나 레지스터에서만 작동하는 RISC 프로세스가 있습니다. ;)

많은 Intel x86 / Amd x64 디자인은 역사적입니다.


0

Big-endian은 일부 연산 (8 진수 길이의 동일한 스프링의 "빅넘"비교)에 유용합니다. 다른 사람들을위한 리틀 엔디안 (아마도 두 개의 "큰 숫자"추가). 결국, 그것은 CPU 하드웨어가 무엇을 위해 설정 되었느냐에 달려 있으며, 보통 하나 또는 다른 것입니다 (일부 MIPS 칩은 IIRC, 부팅시 LE 또는 BE로 전환 가능).


0

가변 길이의 저장 및 전송 만 포함되지만 여러 값을 갖는 산술이없는 경우 LE는 일반적으로 작성하기 쉽고 BE는 읽기 쉽습니다.

구체적인 예로 int-to-string 변환을 수행해 봅시다.

int val_int = 841;
char val_str[] = "841";

int가 문자열로 변환되면 가장 작은 자릿수는 가장 중요한 자릿수보다 추출하기 쉽습니다. 간단한 종료 조건을 가진 간단한 루프에서 모두 수행 할 수 있습니다.

val_int = 841;
// Make sure that val_str is large enough.

i = 0;
do // Write at least one digit to care for val_int == 0
{
    // Constants, can be optimized by compiler.
    val_str[i] = '0' + val_int % 10;
    val_int /= 10;
    i++;
}
while (val_int != 0);

val_str[i] = '\0';
// val_str is now in LE "148"
// i is the length of the result without termination, can be used to reverse it

이제 BE 순서대로 시도하십시오. 일반적으로 특정 수 (여기서는 100)에 대해 최대 10의 거듭 제곱을 갖는 다른 제수가 필요합니다. 물론 이것을 먼저 찾아야합니다. 할 일이 훨씬 더 많습니다.

역 쓰기 조작으로 수행되면 BE에서 문자열을 정수로 변환하는 것이 더 쉽습니다. 쓰기는 가장 중요한 숫자를 마지막에 저장하므로 먼저 읽어야합니다.

val_int = 0;
length = strlen(val_str);

for (i = 0; i < length; i++)
{
    // Again a simple constant that can be optimized.
    val_int = 10*val_int + (val_str[i] - '0');
}

이제 LE 순서대로 동일하게 수행하십시오. 다시 한번, 1로 시작하고 각 자리수에 10을 곱한 추가 요소가 필요합니다.

따라서 값을 정확히 한 번 작성하지만 적어도 한 번 이상 여러 번 읽을 수 있으므로 저장에 BE를 사용하는 것이 좋습니다. 더 간단한 구조를 위해 일반적으로 경로를 이동하여 LE로 변환 한 다음 값을 두 번 쓰더라도 결과를 반대로 바꿉니다.

BE 스토리지의 다른 예로는 UTF-8 인코딩 등이 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.