C語(yǔ)言大小端模式、判斷大小端、大小端轉(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 語(yǔ)言中,有占 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,說(shuō)明數(shù)據(jù)的低字節(jié)在內(nèi)存的低地址存放
// 大端:返回 0,說(shuō)明數(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,說(shuō)明數(shù)據(jù)的低字節(jié)在內(nèi)存的低地址存放
// 大端:返回 0,說(shuō)明數(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,說(shuō)明數(shù)據(jù)的低字節(jié)在內(nèi)存的低地址存放
// 大端:返回 0,說(shuō)明數(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位無(wú)符號(hào)整型的主機(jī)字節(jié)序轉(zhuǎn)成網(wǎng)絡(luò)字節(jié)序
- htons(uint16_t hostshort) // host to network short,16位無(wú)符號(hào)短整型的主機(jī)字節(jié)序轉(zhuǎn)成網(wǎng)絡(luò)字節(jié)序
- ntohl(uint32_t netlong) // network to host long,32位無(wú)符號(hào)整型的網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)成主機(jī)字節(jié)順序的
- ntohs(uint16_t netshort) //16位無(wú)符號(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ù)
直接通過(guò)對(duì)地址的操作來(lái)實(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語(yǔ)言大小端模式、判斷大小端、大小端轉(zhuǎn)換的文章就介紹到這了,更多相關(guān)C語(yǔ)言判斷大小端、大小端轉(zhuǎn)換內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
超詳細(xì)分析C語(yǔ)言動(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語(yǔ)言中動(dòng)態(tài)內(nèi)存的管理2022-04-04
C語(yǔ)言深入講解動(dòng)態(tài)內(nèi)存分配函數(shù)的使用
這篇文章主要介紹了C語(yǔ)言動(dòng)態(tài)內(nèi)存分配,C語(yǔ)言內(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種方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-02-02
C語(yǔ)言詳細(xì)實(shí)現(xiàn)猜拳游戲流程
在學(xué)習(xí)了循環(huán)、分支、和函數(shù)之后,可以寫一些簡(jiǎn)單的小游戲來(lái)給自己的編程之路增添一份樂趣。不僅提升了編碼能力,還可以邊學(xué)邊玩,簡(jiǎn)直妙哉妙哉2022-05-05
C++獲取多瀏覽器上網(wǎng)歷史記錄示例代碼(支持獲取IE/Chrome/FireFox)
這篇文章主要介紹了C++獲取多瀏覽器上網(wǎng)歷史記錄示例代碼,支持獲取IE, Chrome,FireFox等瀏覽器2013-11-11
C語(yǔ)言實(shí)現(xiàn)自動(dòng)存取款機(jī)模擬系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)自動(dòng)存取款機(jī)模擬系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05
C++實(shí)現(xiàn)優(yōu)酷土豆去視頻廣告的方法
這篇文章主要介紹了C++實(shí)現(xiàn)優(yōu)酷土豆去視頻廣告的方法,實(shí)例分析了C++實(shí)現(xiàn)屏蔽功能的相關(guān)技巧,需要的朋友可以參考下2015-04-04

