C語言大小端模式、判斷大小端、大小端轉(zhuǎn)換方法詳解
1. 什么是大端和小端
對(duì)于一個(gè)存儲(chǔ)空間大于 1 個(gè)字節(jié)的數(shù)據(jù),在內(nèi)存中有兩種存儲(chǔ)模式,
大端模式 (big-endian):數(shù)據(jù)的高字節(jié)在內(nèi)存的低地址存放,數(shù)據(jù)的低字節(jié)在內(nèi)存的高地址存放
小端模式 (little-endian):數(shù)據(jù)的高字節(jié)在內(nèi)存的高地址存放,數(shù)據(jù)的低字節(jié)在內(nèi)存的低地址存放
簡(jiǎn)單記憶:
大端模式:大高低
小端模式:小低低
比如,比如數(shù)字:0x12345678,大小端存儲(chǔ)模式如下:
2.為什么會(huì)存在大小端的問題
在 C 語言中,有占 1 個(gè)字節(jié)內(nèi)存空間的 char 類型,占 2 個(gè)字節(jié)內(nèi)存空間的 short int 類型,以及占 4 個(gè)字節(jié)內(nèi)存空間的 int,double 類型和占 8 個(gè)字節(jié)內(nèi)存空間的 double 類型等等,那么對(duì)于大于 1 個(gè)字節(jié)空間的數(shù)據(jù)類型的數(shù)據(jù)在內(nèi)存中存儲(chǔ)時(shí),就必然產(chǎn)生一個(gè)數(shù)據(jù)在內(nèi)存中應(yīng)該將其低字節(jié)數(shù)據(jù)安排在內(nèi)存的低地址還是高地址呢?,對(duì)這個(gè)問題做的不同選擇,就形成了大小端問題。
3. 判斷主機(jī)字節(jié)序 (主機(jī)大小端)
3.1 使用聯(lián)合體 (union)
聯(lián)合體的每一個(gè)成員共用一個(gè)內(nèi)存地址,修改其中一個(gè)成員的數(shù)據(jù),可能會(huì)影響其它成員的數(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 強(qiáng)制轉(zhuǎn)為 char 類型法
#include <stdio.h> int is_little_endian() { int i = 1; // (char)i : 強(qiáng)轉(zhuǎn)為 char 類型,實(shí)際就是取 i 在內(nèi)存中第一個(gè)字節(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ù),并打印本機(jī)字節(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; // 目標(biāo)數(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位無符號(hào)整型的主機(jī)字節(jié)序轉(zhuǎn)成網(wǎng)絡(luò)字節(jié)序
- htons(uint16_t hostshort) // host to network short,16位無符號(hào)短整型的主機(jī)字節(jié)序轉(zhuǎn)成網(wǎng)絡(luò)字節(jié)序
- ntohl(uint32_t netlong) // network to host long,32位無符號(hào)整型的網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)成主機(jī)字節(jié)順序的
- ntohs(uint16_t netshort) //16位無符號(hào)短整型的網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)成主機(jī)字節(jié)序
網(wǎng)絡(luò)字節(jié)序:大端模式(big-endian),即數(shù)據(jù)的高字節(jié)在內(nèi)存的高地址存放,數(shù)據(jù)的低字節(jié)在內(nèi)存的低地址存放。
附:大小端轉(zhuǎn)換函數(shù)
直接通過對(duì)地址的操作來實(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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
超詳細(xì)分析C語言動(dòng)態(tài)內(nèi)存管理問題
動(dòng)態(tài)內(nèi)存是相對(duì)靜態(tài)內(nèi)存而言的。所謂動(dòng)態(tài)和靜態(tài)就是指內(nèi)存的分配方式。動(dòng)態(tài)內(nèi)存是指在堆上分配的內(nèi)存,而靜態(tài)內(nèi)存是指在棧上分配的內(nèi)存,本文帶你深入探究C語言中動(dòng)態(tài)內(nèi)存的管理2022-04-04C語言深入講解動(dòng)態(tài)內(nèi)存分配函數(shù)的使用
這篇文章主要介紹了C語言動(dòng)態(tài)內(nèi)存分配,C語言內(nèi)存管理相關(guān)的函數(shù)主要有realloc、calloc、malloc、free、柔性數(shù)組等,下面這篇文章帶大家了解一下2022-05-05單鏈表實(shí)現(xiàn)反轉(zhuǎn)的3種方法示例代碼
單鏈表的反轉(zhuǎn)是常見的面試題目,下面這篇文章主要給大家介紹了關(guān)于單鏈表實(shí)現(xiàn)反轉(zhuǎn)的3種方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-02-02C++獲取多瀏覽器上網(wǎng)歷史記錄示例代碼(支持獲取IE/Chrome/FireFox)
這篇文章主要介紹了C++獲取多瀏覽器上網(wǎng)歷史記錄示例代碼,支持獲取IE, Chrome,FireFox等瀏覽器2013-11-11C語言實(shí)現(xiàn)自動(dòng)存取款機(jī)模擬系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)自動(dòng)存取款機(jī)模擬系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05C++實(shí)現(xiàn)優(yōu)酷土豆去視頻廣告的方法
這篇文章主要介紹了C++實(shí)現(xiàn)優(yōu)酷土豆去視頻廣告的方法,實(shí)例分析了C++實(shí)現(xiàn)屏蔽功能的相關(guān)技巧,需要的朋友可以參考下2015-04-04