C語言大小端模式、判斷大小端、大小端轉(zhuǎn)換方法詳解
1. 什么是大端和小端
對于一個存儲空間大于 1 個字節(jié)的數(shù)據(jù),在內(nèi)存中有兩種存儲模式,
大端模式 (big-endian):數(shù)據(jù)的高字節(jié)在內(nèi)存的低地址存放,數(shù)據(jù)的低字節(jié)在內(nèi)存的高地址存放
小端模式 (little-endian):數(shù)據(jù)的高字節(jié)在內(nèi)存的高地址存放,數(shù)據(jù)的低字節(jié)在內(nèi)存的低地址存放
簡單記憶:
大端模式:大高低
小端模式:小低低
比如,比如數(shù)字:0x12345678,大小端存儲模式如下:
2.為什么會存在大小端的問題
在 C 語言中,有占 1 個字節(jié)內(nèi)存空間的 char 類型,占 2 個字節(jié)內(nèi)存空間的 short int 類型,以及占 4 個字節(jié)內(nèi)存空間的 int,double 類型和占 8 個字節(jié)內(nèi)存空間的 double 類型等等,那么對于大于 1 個字節(jié)空間的數(shù)據(jù)類型的數(shù)據(jù)在內(nèi)存中存儲時,就必然產(chǎn)生一個數(shù)據(jù)在內(nèi)存中應(yīng)該將其低字節(jié)數(shù)據(jù)安排在內(nèi)存的低地址還是高地址呢?,對這個問題做的不同選擇,就形成了大小端問題。
3. 判斷主機字節(jié)序 (主機大小端)
3.1 使用聯(lián)合體 (union)
聯(lián)合體的每一個成員共用一個內(nèi)存地址,修改其中一個成員的數(shù)據(jù),可能會影響其它成員的數(shù)據(jù)的值。比如以下聯(lián)合體,成本變量 i 和 c 的內(nèi)存地址是相同的,它的內(nèi)存分布示意圖為
union { int i; char c; }un; // 匿名聯(lián)合體
#include <stdio.h> int is_little_endian() { union { int i; char c; }un; // 匿名聯(lián)合體 un.i = 1; return un.c; // 小端:返回 1,說明數(shù)據(jù)的低字節(jié)在內(nèi)存的低地址存放 // 大端:返回 0,說明數(shù)據(jù)的低字節(jié)在內(nèi)存的高地址存放 } int main() { if (is_little_endian()) printf("little-endian\n"); else printf("big-endian\n"); return 0; }
3.2 使用指針
#include <stdio.h> int is_little_endian() { int i = 1; // 等同于 char* p = (char*)&i; return *p; return *(char*)&i; // 小端:返回 1,說明數(shù)據(jù)的低字節(jié)在內(nèi)存的低地址存放 // 大端:返回 0,說明數(shù)據(jù)的低字節(jié)在內(nèi)存的高地址存放 } int main() { if (is_little_endian()) printf("little-endian\n"); else printf("big-endian\n"); return 0; }
3.3 強制轉(zhuǎn)為 char 類型法
#include <stdio.h> int is_little_endian() { int i = 1; // (char)i : 強轉(zhuǎn)為 char 類型,實際就是取 i 在內(nèi)存中第一個字節(jié)的數(shù)據(jù) return (char)i; // 小端:返回 1,說明數(shù)據(jù)的低字節(jié)在內(nèi)存的低地址存放 // 大端:返回 0,說明數(shù)據(jù)的低字節(jié)在內(nèi)存的高地址存放 } int main() { if (is_little_endian()) printf("little-endian\n"); else printf("big-endian\n"); return 0; }
4. 大小端轉(zhuǎn)換
1. 編寫大小端轉(zhuǎn)化函數(shù),并打印本機字節(jié)序下的數(shù)字:0x11223344,分別在小端模式和大端模式下是什么數(shù)據(jù)。
#include <stdio.h> int is_little_endian(); int to_opposite_endian(int data); int to_big_endian(int data); int to_little_endian(int data); int main() { int i = 0x11223344; printf("little_endian: %x\n", to_little_endian(i)); printf("big_endian: %x\n", to_big_endian(i)); return 0; } int is_little_endian() { int i = 1; return (char)i; // 小端:返回 1,大端:返回 0 } // 大小端轉(zhuǎn)換 int to_opposite_endian(int data) { int size = sizeof(data); int des = 0; // 目標數(shù)據(jù) int mask = 0xff; // 掩碼 int temp; for (int i = 0; i < size; i++) { des = des << 8; // 左移8位 temp = data & mask; // 取值 temp = temp >> i * 8; // 移到低8位 des |= temp; mask = mask << 8; // 掩碼左移8位,為下一次取數(shù)據(jù)用 } return des; } int to_big_endian(int data) { if (!is_little_endian()) // 大端 return data; return to_opposite_endian(data); } int to_little_endian(int data) { if (is_little_endian()) // 小端 return data; return to_opposite_endian(data); }
2. 在網(wǎng)絡(luò)編程中,可以使用 htonl, htons, ntohl, ntohs 等函數(shù)
- htonl(uint32_t hostlong) // host to network long,32位無符號整型的主機字節(jié)序轉(zhuǎn)成網(wǎng)絡(luò)字節(jié)序
- htons(uint16_t hostshort) // host to network short,16位無符號短整型的主機字節(jié)序轉(zhuǎn)成網(wǎng)絡(luò)字節(jié)序
- ntohl(uint32_t netlong) // network to host long,32位無符號整型的網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)成主機字節(jié)順序的
- ntohs(uint16_t netshort) //16位無符號短整型的網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)成主機字節(jié)序
網(wǎng)絡(luò)字節(jié)序:大端模式(big-endian),即數(shù)據(jù)的高字節(jié)在內(nèi)存的高地址存放,數(shù)據(jù)的低字節(jié)在內(nèi)存的低地址存放。
附:大小端轉(zhuǎn)換函數(shù)
直接通過對地址的操作來實現(xiàn) 傳入的變量為32位的變量
中間變量ptr是傳入變量的地址
void swap16(void * p) { uint16_t *ptr=p; uint16_t x = *ptr; x = (x << 8) | (x >> 8); *ptr=x; } void swap32(void * p) { uint32_t *ptr=p; uint32_t x = *ptr; x = (x << 16) | (x >> 16); x = ((x & 0x00FF00FF) << 8) | ((x >> 8) & 0x00FF00FF); *ptr=x; } void swap64(void * p) { uint64_t *ptr=p; uint64_t x = *ptr; x = (x << 32) | (x >> 32); x = ((x & 0x0000FFFF0000FFFF) << 16) | ((x >> 16) & 0x0000FFFF0000FFFF); x = ((x & 0x00FF00FF00FF00FF) << 8) | ((x >> 8) & 0x00FF00FF00FF00FF); *ptr=x; }
總結(jié)
到此這篇關(guān)于C語言大小端模式、判斷大小端、大小端轉(zhuǎn)換的文章就介紹到這了,更多相關(guān)C語言判斷大小端、大小端轉(zhuǎn)換內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言深入講解動態(tài)內(nèi)存分配函數(shù)的使用
這篇文章主要介紹了C語言動態(tài)內(nèi)存分配,C語言內(nèi)存管理相關(guān)的函數(shù)主要有realloc、calloc、malloc、free、柔性數(shù)組等,下面這篇文章帶大家了解一下2022-05-05C++獲取多瀏覽器上網(wǎng)歷史記錄示例代碼(支持獲取IE/Chrome/FireFox)
這篇文章主要介紹了C++獲取多瀏覽器上網(wǎng)歷史記錄示例代碼,支持獲取IE, Chrome,FireFox等瀏覽器2013-11-11