Từ 1 tới 4 trên tổng số 4 kết quả

Đề tài: Big and Little Endian Byte Order

  1. #1
    Ngày gia nhập
    04 2009
    Nơi ở
    một căn hộ nhỏ trên trái đất
    Bài viết
    372

    Question Big and Little Endian Byte Order

    Các bạn cần đọc bài trình bày sau về Tổ chức dữ liệu trong bộ nhớ máy tính ở đường link sau: http://www.mediafire.com/?googyqto3jm
    Để đọc được bài này, yêu cầu phải ở trình độ 'quan tâm tới máy tính' và hiểu biết cách đổi số thập phân sang hệ cơ số khác như hex, nhị phân...
    Bài viết của mình trên mạng ở đây là phần bổ sung cho những gì đã có trong bản doc.
    -----------------------------------------------------------------------------------------------

    Trong bài viết trên mình đã nói đến big endian và little endian. Endian là cách tổ chức dữ liệu trên hẳn một nền tảng máy tính, chứ không chỉ đơn thuần là hệ điều hành. Các máy tính theo big endian là Motorola hay dòng Power PC của Mac, còn máy tính theo little endian là intel x86, 6502.... Mình biết phần lớn các bạn đều mua bộ xử lý của intel, vậy nên máy chúng ta là theo little endian.
    Bây giờ mình sẽ dùng đoạn mã viết bằng C/C++ để mô tả những gì đã nói trong bản doc.

    Con trỏ trong C/C++ là một kiểu dữ liệu dùng để lưu giữ địa chỉ của một ô nhớ nào đó trong máy tính. Khi ta dùng khai báo void *p1, float *p2, int *p3 thì tất cả đều là con trỏ có độ dài 4 byte (trong môi trường 32 bit). Tất cả các kiểu con trỏ trỏ đến kiểu dữ liệu khác như int, char, double... đều là con trỏ kiểu void. Ta có thể dùng biểu thức gán: p1=p2 mà không cần đến ép kiểu. Sự khác nhau giữa con trỏ void với các con trỏ khác là ở chỗ con trỏ void không thể đề tham chiếu tức là xác định giá trị mà nó trỏ tới thông qua toán tử *. Đây là ví dụ minh họa
    PHP Code:
    int a=4;
    int *pa=&a;
    void *vp;
    vp=pa;
    printf("%d",*pa)//ok, in ra 4
    printf("%d",*vp)//không được, lỗi 
    Như đã nói ở trong bài doc, khi nhắc đến địa chỉ của một dữ liệu nào đó trong máy tính, ta luôn dùng địa chỉ của byte đầu tiên nằm trong dữ liệu đó làm đại diện cho địa chỉ của dữ liệu đó. Lấy trường hợp con trỏ trỏ đến biến int làm ví dụ. Kiểu int có độ dài 4 byte. vậy một con trỏ trỏ đến biến int sẽ có giá trị là địa chỉ của byte đầu tiên trong 4 byte mô tả giá trị int đó. Lấy trường hợp con trỏ pa ở trên, khi ta dùng toán tử đề tham chiếu *, *pa sẽ có giá trị bằng 4. Máy tính làm thế được vì nó biết pa là con trỏ trỏ đến biến int có độ dài 4 byte, mà pa là địa chỉ của byte đầu, vậy nó hiểu sẽ phải đọc kế thêm 3 byte tiếp theo nữa nằm ở các ô nhớ cao hơn ô nhớ được định danh bởi con trỏ pa, để gộp được thành 4 byte, sau đó chuyển 4 byte đó thành kiểu số nguyên mà chúng ta vẫn rất quen thuộc. Tương tự như vậy nếu ta có con trỏ trỏ đến kiểu char. Char có độ dài 1 byte cho nên khi ta có được con trỏ dạng này, giá trị của con trỏ đó chính là địa chỉ của ô nhớ chứa dữ liệu 1 byte kiểu char:
    PHP Code:
    char c='n';
    char *pc=&c;
    printf("%c",*pc)//ok, in ra 'n' 
    Con trỏ trỏ đến void không thể đề tham chiếu vì máy không thể biết nó phải đọc bao nhiêu byte dữ liệu, và chuyển byte dữ liệu đó thành dữ liệu kiểu gì (kiểu int hay char, hay double...?? rõ ràng nó không biết).
    --------------------------------------------------------------------

    Quay lại với endian, mình sẽ minh họa VD2 trong bài doc bằng mã lệnh C
    Bảng 1:

    PHP Code:
    #include <stdio.h>
    #include <conio.h>


    int main()
    {
        
    chars="ABCD";
        
    unsigned int *pi=(unsigned int *)s;
        
    unsigned short *psi=(unsigned short *)s;
        
    printf("%-15s%-10s%-20s%s","Value","Type","Equivalent_HEX","Memory location\n");
        
    printf("%-15s%-10s",s,"string");
        for(
    int i=0;i<strlen(s);++i)
            
    printf("%.2x",s[i]);//in ra so hex cua tung chu cai
        
    for(int i=0;i<20-8;++i)
            
    printf(" ");
        
    printf("%xh\n",s);
        
    //vi du ve kieu so nguyen ko dau
        
    printf("%-15u%-10s%-20x%xh\n",*pi,"uint",*pi,(void *)pi);
        
    printf("%-15u%-10s%-20x%xh\n",*(psi),"ushort",*psi,(void *)(psi));
        
    printf("%-15u%-10s%-20x%xh\n",*(psi+1),"ushort",*(psi+1),(void *)(psi+1));
        return 
    0;


    Kết quả in ra màn hình có dạng như sau
    Bảng 2:
    Code:
    Value          Type      Equivalent_HEX      Memory location
    ABCD           string    41424344            442000h
    1145258561     uint      44434241            442000h
    16961          ushort    4241                442000h
    17475          ushort    4443                442002h
    Bảng trên thể hiện giá trị, kiểu dữ liệu của giá trị, mã hexa tương đương của giá trị đó và địa chỉ của giá trị đó. Cột địa chỉ của giá trị tùy từng máy sẽ khác nhau, khi biên dịch trên máy mình nó có giá trị là 442000h.
    Như các bạn đã thấy giá trị "ABCD", 1145258561, 16961 đều có cùng một địa chỉ. Áp dụng như những gì có trong bảng 1, ở đây β chính là 442000h.
    Với 3 câu lệnh đầu tiên
    PHP Code:
    chars="ABCD";//s=442000h
    unsigned int *pi=(unsigned int *)s;
    unsigned short *psi=(unsigned short *)s
    Sau khi câu lệnh 1 chạy xong s sẽ có giá trị là 442000h, địa chỉ của byte đầu tiên (byte có giá trị là 'A').
    Sau câu lệnh 2, ta có con trỏ pi cũng có giá trị là 442000h, nhưng lần này con trỏ này trỏ đến kiểu int không âm. Sau câu lệnh 3 ta được con trỏ psi có giá trị 442000h trỏ đến kiểu short không âm.

    Vậy khi ta đề tham chiếu s, ta được "ABCD", nhưng khi ta đề tham chiếu pi, ta được 1145258561 là giá trị nó trỏ đến, vì pi trỏ đến kiểu int 4 byte, nên nó biết ngoài ô nhớ đang được giữ trong pi, nó còn phải đọc thêm 3 ô nhớ cao hơn lần lượt ở các địa chỉ 442001h, 442002h, 442003h:
    • Ô nhớ 442000h: 41h='A'
    • Ô nhớ 442001h: 42h='B'
    • Ô nhớ 442002h: 43h='C'
    • Ô nhớ 442003h: 44h='D'

    Vì máy chúng ta đang dùng là nền tảng intel, vậy nên giá trị của *pi là 44434241h (little endian)
    Với con trỏ psi, kiểu short chỉ có 2 byte, do vậy khi đề tham chiếu máy sẽ đọc 2 ô nhớ là 442000h và 442001h. Khi ấy *psi có giá trị là 4241h. Các bạn có thể nhìn lại bảng 2 để thấy giá trị tương ứng.
    Mình đã in ra giá trị của *pi và *psi thông qua 2 câu lệnh sau:
    PHP Code:
     printf("%-15u%-10s%-20x%xh\n",*pi,"uint",*pi,(void *)pi);// đề tham chiếu giá trị pi
     
    printf("%-15u%-10s%-20x%xh\n",*(psi),"ushort",*psi,(void *)(psi));// đề tham chiếu giá trị psi 
    Sau đó mình tăng tạm thời giá trị của psi lên 1 thông qua biểu thức psi+1. Vì psi là con trỏ trỏ đến kiểu dữ liệu 2 byte cho nên khi tăng psi lên 1 đơn vị nó sẽ dịch đi 2 ô nhớ lên cao so với ô nhớ hiện có. Tức là psi+1 = 442002h. Như các bạn thấy trong bảng 2 *(psi+1) là 4443h.
    PHP Code:
    printf("%-15u%-10s%-20x%xh\n",*(psi+1),"ushort",*(psi+1),(void *)(psi+1));//đề tham chiếu psi+1 
    Being top programmers always requires advanced knowledge of C/C++ and assembly


  2. #2
    Ngày gia nhập
    01 2010
    Nơi ở
    до свидания!
    Bài viết
    1,766

    Ôi, thật đẳng cấp. Tôi rất thích chủ đề này....

  3. #3
    Ngày gia nhập
    03 2009
    Nơi ở
    C:\Windows\system32
    Bài viết
    18

    sao mà thấy khó quá đi, đẳng cấp quá!

  4. #4
    Ngày gia nhập
    06 2007
    Nơi ở
    C:\WINDOWS\system32\dllcache\
    Bài viết
    3,007

    Chi tiết hơn nữa về câu nói của icttrack , Endian là cách tổ chức dữ liệu trên hẳn một nền tảng máy tính.
    icttrack nói rất đúng , langman có học qua về điện tử và nhúng, có thấy nhiều CPU trong các thiết bị điện tử đặc biệt của dòng Motorola nó được theo big endian. Các CPU ít tên tuổi hơn thì theo mô hình của intel.
    Không chỉ là trong CPU, trong các PIC cũng vậy, chúng đều theo little endian


    Các bạn có thể khám phá điều này qua việc dump memory trong các thiết bị số ví dụ như trong đt motorola của bạn !!!
    Đã được chỉnh sửa lần cuối bởi langman : 03-03-2010 lúc 02:44 PM.
    ^_,^

    Facebook : https://www.facebook.com/langmaninternet

    Bùi Tấn Quang

Các đề tài tương tự

  1. Thư viện để xử lý byte order, endianness...
    Gửi bởi doicanhden trong diễn đàn Thủ thuật, Tutorials và Mã nguồn C/C++/C++0x
    Trả lời: 0
    Bài viết cuối: 26-05-2013, 01:53 AM
  2. Lập trình C chia số 2 byte cho số 1 byte và cho kết quả thương là số 2 byte và phần dư là số 1 byte
    Gửi bởi sakurai111 trong diễn đàn Thắc mắc lập trình C/C++/C++0x
    Trả lời: 0
    Bài viết cuối: 17-11-2012, 10:58 PM
  3. Nhận order web UK, order web UK giá cạnh tranh - 0121 824 8957
    Gửi bởi qctructuyen03 trong diễn đàn Giới thiệu website, sản phẩm của bạn
    Trả lời: 0
    Bài viết cuối: 11-05-2012, 11:39 PM
  4. Cách chuyển đổi một số từ dạng Little Endian sang Big Endian
    Gửi bởi minhtuan.a0 trong diễn đàn Nhập môn lập trình C/C++
    Trả lời: 4
    Bài viết cuối: 07-12-2011, 10:15 PM

Quyền hạn của bạn

  • Bạn không thể gửi đề tài mới
  • Bạn không thể gửi bài trả lời
  • Bạn không thể gửi các đính kèm
  • Bạn không thể chỉnh sửa bài viết của bạn