Bộ xử lý Intel (và có thể một số người khác) sử dụng định dạng endian nhỏ để lưu trữ.
Tôi luôn tự hỏi tại sao ai đó muốn lưu trữ các byte theo thứ tự ngược lại. Định dạng này có bất kỳ lợi thế so với định dạng endian lớn?
Bộ xử lý Intel (và có thể một số người khác) sử dụng định dạng endian nhỏ để lưu trữ.
Tôi luôn tự hỏi tại sao ai đó muốn lưu trữ các byte theo thứ tự ngược lại. Định dạng này có bất kỳ lợi thế so với định dạng endian lớn?
Câu trả lời:
Dù sao cũng có các đối số, nhưng có một điểm là trong một hệ thống cuối nhỏ, địa chỉ của một giá trị đã cho trong bộ nhớ, được lấy theo chiều rộng 32, 16 hoặc 8 bit, là như nhau.
Nói cách khác, nếu trong bộ nhớ bạn có giá trị hai byte:
0x00f0 16
0x00f1 0
lấy '16' làm giá trị 16 bit (c 'ngắn' trên hầu hết các hệ thống 32 bit) hoặc làm giá trị 8 bit (thường là c 'char') chỉ thay đổi hướng dẫn tìm nạp bạn sử dụng - không phải địa chỉ bạn tìm nạp từ.
Trên một hệ thống lớn, với những điều trên được trình bày là:
0x00f0 0
0x00f1 16
bạn sẽ cần tăng con trỏ và sau đó thực hiện thao tác tìm nạp hẹp hơn trên giá trị mới.
Vì vậy, trong ngắn hạn, 'trên các hệ thống endian nhỏ, dàn diễn viên là không có.'
Tôi luôn tự hỏi tại sao ai đó muốn lưu trữ các byte theo thứ tự ngược lại.
Big endian và little endian chỉ là "trật tự bình thường" và "trật tự ngược" theo quan điểm của con người, và sau đó chỉ khi tất cả những điều này là đúng ...
Đó là tất cả các quy ước của con người hoàn toàn không quan trọng đối với CPU. Nếu bạn giữ lại số 1 và số 2, và lật số 3, người cuối cùng có vẻ "hoàn toàn tự nhiên" đối với những người đọc tiếng Ả Rập hoặc tiếng Do Thái, được viết từ phải sang trái.
Và có những quy ước khác của con người khiến cho những người lớn cuối cùng có vẻ không tự nhiên, như ...
Quay lại khi tôi chủ yếu lập trình 68K và PowerPC, tôi đã coi big-end là "đúng" và endian nhỏ là "sai". Nhưng vì tôi đã làm nhiều công việc của ARM và Intel hơn, tôi đã quen với người cuối cùng. Nó thực sự không quan trọng.
OK, đây là lý do như tôi đã giải thích cho tôi: Phép cộng và phép trừ
Khi bạn thêm hoặc trừ các số nhiều byte, bạn phải bắt đầu với byte có ý nghĩa nhỏ nhất. Ví dụ: nếu bạn thêm hai số 16 bit, có thể có một số mang từ byte có ý nghĩa nhỏ nhất đến byte có ý nghĩa nhất, vì vậy bạn phải bắt đầu với byte có ý nghĩa nhỏ nhất để xem có mang hay không. Đây là cùng một lý do mà bạn bắt đầu với chữ số ngoài cùng bên phải khi thực hiện bổ sung thủ công. Bạn không thể bắt đầu từ bên trái.
Hãy xem xét một hệ thống 8 bit lấy byte theo tuần tự từ bộ nhớ. Nếu nó tìm nạp byte có ý nghĩa nhỏ nhất trước tiên , nó có thể bắt đầu thực hiện phép cộng trong khi byte quan trọng nhất đang được tìm nạp từ bộ nhớ. Sự song song này là lý do tại sao hiệu suất tốt hơn trong ít endian trên như hệ thống. Nếu phải đợi cho đến khi cả hai byte được tìm nạp từ bộ nhớ hoặc tìm nạp chúng theo thứ tự ngược lại, sẽ mất nhiều thời gian hơn.
Đây là trên các hệ thống 8 bit cũ. Trên một CPU hiện đại, tôi nghi ngờ thứ tự byte tạo ra bất kỳ sự khác biệt nào và chúng tôi chỉ sử dụng ít endian vì lý do lịch sử.
Với bộ xử lý 8 bit, nó chắc chắn hiệu quả hơn, bạn có thể thực hiện thao tác 8 hoặc 16 bit mà không cần mã khác và không cần đệm thêm giá trị.
Nó vẫn tốt hơn cho một số hoạt động bổ sung nếu bạn đang xử lý một byte tại một thời điểm.
Nhưng không có lý do gì mà big-endian tự nhiên hơn - trong tiếng Anh, bạn sử dụng mười ba (endian nhỏ) và hai mươi ba (endian lớn)
0x12345678
được lưu trữ 78 56 34 12
trong khi trên hệ thống BE thì 12 34 56 78
(byte 0 ở bên trái, byte 3 ở bên phải). Lưu ý số lượng càng lớn (tính theo bit), yêu cầu trao đổi càng nhiều; một WORD sẽ yêu cầu một trao đổi; một DWORD, hai lượt đi (ba lần hoán đổi tổng cộng); một QWORD ba lần vượt qua (tổng cộng 7), v.v. Đó là, (bits/8)-1
hoán đổi. Một tùy chọn khác là đọc cả hai tiến và lùi (đọc từng byte về phía trước, nhưng quét toàn bộ # ngược).
Quy ước ngày của Nhật Bản là "big endian" - yyyy / mm / dd. Điều này rất thuận tiện cho việc sắp xếp các thuật toán, có thể sử dụng một chuỗi so sánh đơn giản với quy tắc ký tự đầu tiên thông thường là quan trọng nhất.
Một cái gì đó tương tự áp dụng cho các số cuối lớn được lưu trữ trong một bản ghi đầu tiên có ý nghĩa nhất. Thứ tự quan trọng của các byte trong các trường khớp với tầm quan trọng của các trường trong bản ghi, vì vậy bạn có thể sử dụng a memcmp
để so sánh các bản ghi, không quan tâm nhiều đến việc bạn có so sánh hai từ khóa dài, bốn từ hoặc tám byte riêng biệt hay không.
Lật thứ tự quan trọng của các trường và bạn có được lợi thế tương tự, nhưng đối với các số ít về cuối hơn là cuối lớn.
Điều này có rất ít ý nghĩa thực tế, tất nhiên. Cho dù nền tảng của bạn là lớn cuối hay cuối nhỏ, bạn có thể đặt hàng các trường bản ghi để khai thác thủ thuật này nếu bạn thực sự cần. Đó chỉ là một nỗi đau nếu bạn cần viết mã di động .
Tôi cũng có thể bao gồm một liên kết đến sự hấp dẫn cổ điển ...
http://tools.ietf.org/rfcmarkup?url=ftp://ftp.rfc-editor.org/in-notes/ien/ien137.txt
BIÊN TẬP
Một suy nghĩ thêm. Tôi đã từng viết một thư viện số nguyên lớn (để xem nếu tôi có thể) và vì thế, các khối rộng 32 bit được lưu trữ theo thứ tự nhỏ, bất kể cách nền tảng sắp xếp các bit trong các khối đó. Lý do là ...
Rất nhiều thuật toán tự nhiên bắt đầu hoạt động ở đầu cuối ít quan trọng nhất và muốn các đầu cuối đó được khớp. Ví dụ, ngoài ra, mang theo propogate với các chữ số ngày càng quan trọng hơn, do đó, có ý nghĩa để bắt đầu ở đầu ít quan trọng nhất.
Tăng hoặc thu hẹp một giá trị chỉ có nghĩa là thêm / xóa các đoạn ở cuối - không cần phải thay đổi khối lên / xuống. Sao chép có thể vẫn cần thiết do phân bổ lại bộ nhớ, nhưng không thường xuyên.
Tất nhiên, điều này không liên quan đến bộ xử lý - cho đến khi CPU được tạo ra với sự hỗ trợ số nguyên lớn về phần cứng, đó hoàn toàn là một thứ trong thư viện.
Không ai khác đã trả lời TẠI SAO điều này có thể được thực hiện, rất nhiều thứ về hậu quả.
Hãy xem xét một bộ xử lý 8 bit có thể tải một byte từ bộ nhớ trong một chu kỳ xung nhịp nhất định.
Bây giờ, nếu bạn muốn tải một giá trị 16 bit, vào (giả sử) thanh ghi một và chỉ 16 bit mà bạn có - tức là bộ đếm chương trình, thì một cách đơn giản để làm điều đó là:
kết quả: bạn chỉ tăng vị trí tìm nạp, bạn chỉ tải vào phần thứ tự thấp của thanh ghi rộng hơn và bạn chỉ cần có thể dịch chuyển sang trái. (Tất nhiên, dịch chuyển sang phải là hữu ích cho các hoạt động khác vì vậy hoạt động này là một chút của một chương trình bên lề.)
Một hậu quả của điều này là các công cụ 16 bit (byte kép) được lưu trữ theo thứ tự Most..Least. Tức là, địa chỉ nhỏ hơn có byte đáng kể nhất - rất lớn về cuối.
Thay vào đó, nếu bạn cố tải bằng endian nhỏ, bạn sẽ cần tải một byte vào phần dưới của thanh ghi rộng, sau đó tải byte tiếp theo vào khu vực tổ chức, dịch chuyển nó và sau đó đưa nó vào đầu thanh ghi rộng hơn của bạn . Hoặc sử dụng một sự sắp xếp phức tạp hơn của gating để có thể tải có chọn lọc vào byte trên cùng hoặc dưới cùng.
Kết quả của việc cố gắng đi ít endian là bạn cần nhiều silicon hơn (công tắc và cổng) hoặc nhiều thao tác hơn.
Nói cách khác, trong điều kiện nhận được tiếng nổ trở lại trong những ngày xưa, bạn có nhiều tiếng nổ hơn cho hầu hết hiệu suất và diện tích silicon nhỏ nhất.
Những ngày này, những nhận xét và khá nhiều không thích hợp, nhưng những thứ như đường ống dẫn điền có thể vẫn là một chút của một vấn đề lớn.
Khi nói đến việc viết s / w, cuộc sống thường dễ dàng hơn khi sử dụng địa chỉ endian nhỏ.
(Và bộ xử lý về cuối lớn có xu hướng về cuối lớn về trật tự byte và little endian về bit-in-byte. Nhưng một số bộ vi xử lý là lạ và sẽ sử dụng chút về cuối lớn đặt hàng cũng như byte đặt hàng. Này làm cho cuộc sống rất thú vị cho nhà thiết kế h / w thêm các thiết bị ngoại vi được ánh xạ bộ nhớ nhưng không có kết quả nào khác đối với người lập trình.)
jimwise đã làm một điểm tốt. Có một vấn đề khác, trong endian nhỏ bạn có thể làm như sau:
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
Thẳng thắn hơn cho các lập trình viên không bị ảnh hưởng bởi nhược điểm rõ ràng của các vị trí bị tráo đổi trong bộ nhớ. Cá nhân tôi thấy endian lớn là nghịch đảo của những gì là tự nhiên :). 12 nên được lưu trữ và viết là 21 :)
for(i=0; i<4; i++) { num += data[i] << (24 - i * 8); }
tương ứng với move.l data, num
CPU endian lớn.
Tôi luôn tự hỏi tại sao ai đó muốn lưu trữ các byte theo thứ tự ngược lại
Số thập phân được viết lớn về cuối. Nó cũng là cách bạn viết nó bằng tiếng Anh Bạn bắt đầu với chữ số có ý nghĩa nhất và chữ số quan trọng nhất tiếp theo đến ít quan trọng nhất. ví dụ
1234
là một nghìn, hai trăm ba mươi bốn.
Đây là cách endian lớn đôi khi được gọi là trật tự tự nhiên.
Trong endian nhỏ, con số này sẽ là một, hai mươi, ba trăm bốn nghìn.
Tuy nhiên, khi bạn thực hiện số học như cộng hoặc trừ, bạn bắt đầu với kết thúc.
1234
+ 0567
====
Bạn bắt đầu với 4 và 7, viết chữ số thấp nhất và ghi nhớ mang theo. Sau đó, bạn thêm 3 và 6, v.v. Để cộng, trừ hoặc so sánh, việc thực hiện sẽ đơn giản hơn, nếu bạn đã có logic để đọc bộ nhớ theo thứ tự, nếu các số bị đảo ngược.
Để hỗ trợ endian lớn theo cách này, bạn cần logic để đọc bộ nhớ ngược lại hoặc bạn có quy trình RISC chỉ hoạt động trên các thanh ghi. ;)
Rất nhiều thiết kế Intel x86 / Amd x64 là lịch sử.
Big-endian rất hữu ích cho một số hoạt động (so sánh "bignums" của lò xo có độ dài octet bằng nhau với tâm trí). Little endian cho người khác (có thể thêm hai "bignums"). Cuối cùng, nó phụ thuộc vào phần cứng CPU đã được thiết lập để làm gì, nó thường là cái này hay cái khác (một số chip MIPS, IIRC, có thể chuyển đổi khi khởi động thành LE hoặc BE).
Khi chỉ lưu trữ và chuyển với độ dài thay đổi được tham gia, nhưng không có số liệu nào có nhiều giá trị, thì LE thường dễ viết hơn, trong khi BE dễ đọc hơn.
Hãy lấy một chuyển đổi int-to-string (và trở lại) làm ví dụ cụ thể.
int val_int = 841;
char val_str[] = "841";
Khi int được chuyển đổi thành chuỗi, thì chữ số có nghĩa nhỏ nhất sẽ dễ trích xuất hơn chữ số có nghĩa nhất. Tất cả có thể được thực hiện trong một vòng lặp đơn giản với một điều kiện kết thúc đơn giản.
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
Bây giờ hãy thử tương tự theo thứ tự BE. Thông thường bạn cần một ước số khác có sức mạnh lớn nhất là 10 cho số cụ thể (ở đây là 100). Trước tiên bạn cần tìm cái này. Nhiều thứ hơn để làm.
Chuyển đổi chuỗi thành int dễ thực hiện hơn trong BE, khi nó được thực hiện dưới dạng thao tác ghi ngược. Viết lưu các chữ số có ý nghĩa nhất cuối cùng, vì vậy nó nên được đọc trước.
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');
}
Bây giờ làm tương tự theo thứ tự LE. Một lần nữa, bạn cần một yếu tố bổ sung bắt đầu bằng 1 và được nhân với 10 cho mỗi chữ số.
Vì vậy, tôi thường thích sử dụng BE để lưu trữ, bởi vì một giá trị được viết chính xác một lần, nhưng đọc ít nhất một lần và có thể nhiều lần. Đối với cấu trúc đơn giản hơn, tôi cũng thường đi theo lộ trình để chuyển đổi sang LE và sau đó đảo ngược kết quả, ngay cả khi nó ghi giá trị lần thứ hai.
Một ví dụ khác cho việc lưu trữ BE sẽ là mã hóa UTF-8 và nhiều hơn nữa.