C語言實(shí)現(xiàn)十六進(jìn)制與二進(jìn)制的相互轉(zhuǎn)換
本文中的代碼可以將文件中的十六進(jìn)制存儲(chǔ)與二進(jìn)制存儲(chǔ)相互轉(zhuǎn)換。
十六進(jìn)制->二進(jìn)制
原理是:每兩位存儲(chǔ)為一個(gè)字符(char)保存。
因?yàn)槭M(jìn)制數(shù)最大為 f,即 15,在內(nèi)存中只需要 4 位就可以表示。而一般情況下一個(gè)字符是占一個(gè)字節(jié) 8 位,所以正好可以存儲(chǔ)十六進(jìn)制兩位。
舉個(gè)栗子:
在文件中存儲(chǔ)十六進(jìn)制為ab,ab轉(zhuǎn)換為二進(jìn)制,就是1010 1011,剛好八位,可以聯(lián)想到ASCII碼,用一個(gè)字符可以表示。
注意轉(zhuǎn)為二進(jìn)制后,前32個(gè)為不可見字符,附圖ASCII碼。

(將十六進(jìn)制轉(zhuǎn)為二進(jìn)制還會(huì)壓縮一倍的空間?因?yàn)閍b本來占兩個(gè)字節(jié),現(xiàn)在轉(zhuǎn)成二進(jìn)制,即一個(gè)char字符,只占用一個(gè)字節(jié)大小。但是轉(zhuǎn)換過程中時(shí)間消耗,我不太確定是否優(yōu)化了)
#include <stdio.h>
int main() {
FILE * in = fopen("./data.txt", "r");
FILE * out = fopen("./data", "w");
while (1) {
char c;
unsigned char d = 0;
for (int i = 0; i < 2; ++i) {
// 從 in 讀取 1 個(gè)大小為 1 字節(jié)數(shù)據(jù)保存在 c
if (fread(&c, 1, 1, in) == 0) {
fclose(in);
fclose(out);
return 0;
}
// 讀到空格或者換行索引需要回退
if (c == ' ' || c == '\n') {
i--;
continue;
}
// 將讀到的十六進(jìn)制字符轉(zhuǎn)成具體的十進(jìn)制數(shù)字
if (c >= '0' && c <= '9') {
c -= '0';
} else if (c >= 'a' && c <= 'f') {
c -= 'a';
c += 10;
} else {
printf("error");
}
//printf("c -> %d \n", c);
d <<= 4;
d |= c;
}
//printf("-------> %c\n", d);
fwrite(&d, 1, 1, out);
}
return 0;
}
核心代碼:
d <<= 4 and d |= c
解釋:
內(nèi)層for循環(huán)為兩次,c讀取兩次:
我們假設(shè)第一次讀到a字符,第二次讀到b字符。
(或運(yùn)算:參加運(yùn)算的兩個(gè)對(duì)象只要有一個(gè)為1,其值為1)
| 操作 | 值 |
|---|---|
| 第一次循環(huán)開始 : | d (0000 0000) c(0000 1010) |
| d <<= 4 : | d (0000 0000) c(0000 1010) |
| d |= c : | d (0000 1010) c(0000 1010) |
| 第二次循環(huán)開始: | d (0000 1010) c(0000 1011) |
| d <<= 4 : | d (1010 0000) c(0000 1011) |
| d |= c : | d (1010 1011) c(0000 1011) |
| 兩次循環(huán)結(jié)束 將d寫入文件,轉(zhuǎn)換完成。 |
如果想知道轉(zhuǎn)換是否正確的話,可以用 hexdump -C + 文件名(data) 檢查一下是否正確。(linux命令)
二進(jìn)制->十六進(jìn)制
這個(gè)就是上邊操作相反的過程,讀取二進(jìn)制文件,然后轉(zhuǎn)成十六進(jìn)制字符保存。
#include <stdio.h>
int main() {
FILE * in = fopen("./data.txt", "r");
FILE * out = fopen("./data", "w");
char space = ' ';
char enter = '\n';
int idx = 0;
while (1) {
char c[2];
unsigned char d = 0;
for (int i = 0; i < 4; ++i) {
// 讀取一個(gè)字節(jié)
if (fread(&d, 1, 1, in) == 0) {
fclose(in);
fclose(out);
return 0;
}
// 一個(gè)二進(jìn)制字節(jié)轉(zhuǎn)回兩個(gè)十六進(jìn)制字符
char mask = 0xf;
c[0] = d >> 4; // 將低位移走就是該字節(jié)保存的第一個(gè)十六進(jìn)制字符
c[1] = d & mask; // 保留 d 的低位就是該字節(jié)保存的第二個(gè)十六進(jìn)制字符
// 將十進(jìn)制數(shù)字轉(zhuǎn)回對(duì)應(yīng)的十六進(jìn)制字符(與上一步轉(zhuǎn)換的代碼相反)
if (c[0] >= 0 && c[0] <= 9) {
c[0] += '0';
} else {
c[0] -= 10;
c[0] += 'a';
}
if (c[1] >= 0 && c[1] <= 9) {
c[1] += '0';
} else {
c[1] -= 10;
c[1] += 'a';
}
// 從 c 地址開始讀取兩個(gè)字節(jié),寫到 out
fwrite(&c, 1, 2, out);
}
// 寫空格或者換行 保持格式
idx++;
if (idx == 4){
idx = 0;
fwrite(&enter, 1, 1, out);
} else {
fwrite(&space, 1, 1, out);
}
}
return 0;
}
mask的二進(jìn)制是0000 1111。
到此這篇關(guān)于C語言實(shí)現(xiàn)十六進(jìn)制與二進(jìn)制的相互轉(zhuǎn)換的文章就介紹到這了,更多相關(guān)C語言 十六進(jìn)制二進(jìn)制互轉(zhuǎn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Linux中rm命令使用以及C/C++代碼實(shí)現(xiàn)
m 是remove 的縮寫,Linux中 rm 命令的功能為刪除一個(gè)目錄中的一個(gè)或多個(gè)文件或目錄,它也可以將某個(gè)目錄及其下的所有文件及子目錄均刪除,這篇文章主要給大家介紹了關(guān)于Linux中rm命令使用以及C/C++代碼實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下2022-04-04
C++實(shí)現(xiàn)Go的defer功能(示例代碼)
defer和go一樣都是Go語言提供的關(guān)鍵字。defer用于資源的釋放,會(huì)在函數(shù)返回之前進(jìn)行調(diào)用。接下來通過本文給大家介紹C++實(shí)現(xiàn)Go的defer功能,感興趣的朋友跟隨小編一起看看吧2021-07-07
C語言實(shí)現(xiàn)簡單的控制臺(tái)三子棋游戲
這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)簡單的控制臺(tái)三子棋游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-11-11
C語言實(shí)現(xiàn)AT指令A(yù)SCII碼的拼接處理流程
今天小編就為大家分享一篇關(guān)于C語言實(shí)現(xiàn)AT指令A(yù)SCII碼的拼接處理流程,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2018-12-12
C++命名空間?缺省參數(shù)?const總結(jié)?引用總結(jié)?內(nèi)聯(lián)函數(shù)?auto關(guān)鍵字詳解
這篇文章主要介紹了C++命名空間?缺省參數(shù)?const總結(jié)?引用總結(jié)?內(nèi)聯(lián)函數(shù)?auto關(guān)鍵字詳解的相關(guān)資料,需要的朋友可以參考下2023-01-01

