پرش به محتویات

Byteorder

مقدمه

byte order یا endianness اشاره میکنه به ترتیبی که بایت های دیتا داخل کامپیوتر ذخیره و خونده میشن. وقتی که دارین به برنامه ورودی میدین یا هگزدامپ(نمایش دیتا در مبنای ۱۶) دیتایی رو میخونین نیاز دارین بدونین اون دیتا یا برنامه از چه byte order استفاده میکنه، وگرنه احتمالا اشتباه چیزی رو تفسیر میکنین و به هدفتون نمیرسین.

little endian

یعنی بایت کم ارزش تر داخل ادرس پایین تر و بایت پر ارزش تر داخل ادرس بالاتر ذخیره شه، این روش پر استفاده ترین داخل کامپیوتر هاست.
با چند مثال میبینیم که چطور دیتا رو به صورت little endian بخونیم یا بدیم به برنامه.

مثال ۱ - دیتا

0x7fffffffcc28: 0x27    0xeb    0xd5    0xf7
این یه تیکه از دیتایی هست که با gdb از حافظه یک برنامه برداشتم(یک هگزدامپ هست)، سمت چپ ترین بایت پایین ترین ادرس و سمت راست ترین بالاترین ادرس رو داره. پس اگه تک تک دیتا و ادرس هاشونو کنار هم بزاریم این شکلی میشه.
               HIGH
               --------
0x7fffffffcc2b | 0xf7 |
               --------
0x7fffffffcc2a | 0xd5 |
               --------
0x7fffffffcc29 | 0xeb |
               --------
0x7fffffffcc28 | 0x27 |
               --------
               LOW

این عدد در واقع هست:

0xf7d5eb27

مثال ۲ - دیتا

0x7fffffffcc48: 0x1a    0x9c    0x55    0xba    0x55    0xec    0x0    0x0
0x7fffffffcc50: 0xfc    0xdc    0xff    0xaf    0xff    0x7f    0x0    0x0

اگه تک تک داده ها و ادرس هاشونو کنار هم بزاریم این شکلی میشه

               HIGH
               --------
0x7fffffffcc57 | 0x00 |
               --------
0x7fffffffcc56 | 0x00 |
               --------
0x7fffffffcc55 | 0x7f |
               --------
0x7fffffffcc54 | 0xff |
               --------
0x7fffffffcc53 | 0xaf |
               --------
0x7fffffffcc52 | 0xff |
               --------
0x7fffffffcc51 | 0xdc |
               --------
0x7fffffffcc50 | 0xfc |
               --------
0x7fffffffcc4f | 0x00 |
               --------
0x7fffffffcc4e | 0x00 |
               --------
0x7fffffffcc4d | 0xec |
               --------
0x7fffffffcc4c | 0x55 |
               --------
0x7fffffffcc4b | 0xba |
               --------
0x7fffffffcc4a | 0x55 |
               --------
0x7fffffffcc49 | 0x9c |
               --------
0x7fffffffcc48 | 0x1a |
               --------
               LOW

که میشه این عدد

0x00007fff,afffdcfc,0000ec55,ba559c1a
, هارو برای خوانایی بیشتر گذاشتم و میتونن در نظر گرفته نشن

مثال ۳ - ورودی/خروجی برنامه

#include <stdio.h>

int main(){
    int buff;
    buff = 0;
    scanf("%s", &buff);
    printf("%p:%x\n", &buff, buff);
} 
└─$ printf '\xba\xbe\xca\xec'  | ./a.out
0x7ffce587f39c:eccabeba

چرا برعکس شد؟
چون بایت کم ارزش عدد سمت راست ترین بایتش هست، ولی وقتی داریم string رو میخونیم کم ارزش ترین بایتش سمت چپ ترینش هست، مثال زیر رو ببینین:

char str[] = "hello";
str[0]; // 'h' 

int number = 0xbafc; //یک عدد رندوم
number & 0x00ff; // 0xfc

big endian

یعنی بایت پرارزش تر توی ادرس های پایین تر و بایت کم ارزش تر توی ادرس های بالاتر قرار بگیره. تعدادی از پردازنده ها از این روش استفاده میکنن ولی بیشترین کاربرد این روش برای پر کردن header های پیام های شبکه هستش. به صورت قراردادی تمام برنامه ها باید header های شبکه رو به صورت big endian پر کنن که ناهماهنگی به وجود نیاد.

مثال - ادرس IP

وقتی که برنامه میخواد به سیستم عامل بگه که ادرس ای پی مقصدش کجاست باید از big endian استفاده کنه که اون ادرس ایپی رو ذخیره کنه.
فرض کنیم که میخوایم به سیستم عامل بگیم میخوایم به ادرس 192.168.178.160 پیام بدیم. این ادرس ایپی رو اینطوری باید توی حافظه ذخیره کنیم:

0: c0 a8 b2 a0
توجه کنین که 0xc0 یعنی ۱۹۲ که توی ادرس پایین تر قرار گرفته.

توابع پر استفاده

htons

این تابع مخفف host to network short هست که میگه ورودی که از نوع short هست ( یک نوع داده داخل زبان c) رو از byteorder کامپیوتر (میتونه little endian یا big endian باشه) تبدیل میکنم به byte order شبکه (که یعنی big endian) این تابع و توابع شبیه اون بهمون کمک میکنن بدون توجه به byte order کامپیوتری که روش برنامه نویسی میکنیم برنامه نویسی کنیم و برنامه مون رو بتونیم روی کامپیوتر هایی که byte order متفاوت دارن کامپایل و اجرا کنیم.

از این تابع نسخه های دیگه هم وجود داره:

  • ntohs: network to host short
  • htonl: host to network long
  • ntohl: network to host long

نویسنده

Ali