本文中的代码可以将文件中的十六进制存储与二进制存储相互转换。
十六进制->二进制
原理是:每两位存储为一个字符(char)保存。
因为十六进制数最大为 f,即 15,在内存中只需要 4 位就可以表示。而一般情况下一个字符是占一个字节 8 位,所以正好可以存储十六进制两位。
举个栗子:
在文件中存储十六进制为ab,ab转换为二进制,就是1010 1011,刚好八位,可以联想到ASCII码,用一个字符可以表示。
注意转为二进制后,前32个为不可见字符,附图ASCII码。
(将十六进制转为二进制还会压缩一倍的空间?因为ab本来占两个字节,现在转成二进制,即一个char字符,只占用一个字节大小。但是转换过程中时间消耗,我不太确定是否优化了)
#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 个大小为 1 字节数据保存在 c
if (fread(&c, 1, 1, in) == 0) {
fclose(in);
fclose(out);
return 0;
}
// 读到空格或者换行索引需要回退
if (c == ' ' || c == '\n') {
i--;
continue;
}
// 将读到的十六进制字符转成具体的十进制数字
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
解释:
内层for循环为两次,c读取两次:
我们假设第一次读到a字符,第二次读到b字符。
(或运算:参加运算的两个对象只要有一个为1,其值为1)
操作 | 值 |
---|---|
第一次循环开始 : | d (0000 0000) c(0000 1010) |
d <<= 4 : | d (0000 0000) c(0000 1010) |
d |= c : | d (0000 1010) c(0000 1010) |
第二次循环开始: | d (0000 1010) c(0000 1011) |
d <<= 4 : | d (1010 0000) c(0000 1011) |
d |= c : | d (1010 1011) c(0000 1011) |
两次循环结束 将d写入文件,转换完成。 |
如果想知道转换是否正确的话,可以用 hexdump -C + 文件名(data) 检查一下是否正确。(linux命令)
二进制->十六进制
这个就是上边操作相反的过程,读取二进制文件,然后转成十六进制字符保存。
#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) {
// 读取一个字节
if (fread(&d, 1, 1, in) == 0) {
fclose(in);
fclose(out);
return 0;
}
// 一个二进制字节转回两个十六进制字符
char mask = 0xf;
c[0] = d >> 4; // 将低位移走就是该字节保存的第一个十六进制字符
c[1] = d & mask; // 保留 d 的低位就是该字节保存的第二个十六进制字符
// 将十进制数字转回对应的十六进制字符(与上一步转换的代码相反)
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 地址开始读取两个字节,写到 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的二进制是0000 1111。
到此这篇关于C语言实现十六进制与二进制的相互转换的文章就介绍到这了,更多相关C语言 十六进制二进制互转内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!