一、计算机的进制
接受过义务教育的,有过数学的初步的知识的都知道,现实世界中,基本是以十进制的方式来组织数据的即如何进行计数。也就是常见的逢十进一。但在计算机世界中,直接用这种方式就比较麻烦了,毕竟计算机中只有两个状态即0和1,所以计算机中基础的数据描述是以二进制进行的(当然前苏联和最近国内某公司都搞了三进制),即逢二进一。
当然,用二进制描述计算机的原始数据是还方便快捷的,但在向上层的应用中,二进制就有些复杂和不容易理解了。所以后来又出现了八进制和十六进制,八进制目前的应用场景已经非常少见了,但十六进制则可以理解成是二进制在计算机在更高层上的优化的表示(其实八进制也可以这样理解,不过,它被十六进制取代了)。
- 二进制(Binary):也就是只有0和1两个数字描述数字,逢2进1,计算机的内部都是以二进制的方式进行描述和处理的。它一般以0b或0B做为前缀,如0b1101
- 八进制(Octal):使用0到7这8个数字描述数字,逢八进一。八进制主要是为了在应用上简化二进制的表示。不过现在已经很少使用了。它一般以0做为前缀,如036
- 十进制(Decimal):现实世界中使用的进制方式,使用0到9这10个数字来描述数字,逢十进一。作为大家日常使用的数字进制,在计算、交易、计量等场景被广泛应用。它没有前缀,如101
- 十六进制(Hexadecimal):使用0到9这10个数字和A到F(或小写a到f)6个字母来描述数字,逢十六进一。在计算机应用中应用非常广泛,比如内存地址、图像描述等等。它一般以0x或0X为前缀,如0x3D
其实无论是多少进制,都是方便人们进行计数的,正如前面说的,不同的应用中,计数的方式可能不一样,哪种更方便,就使用哪种,没有说必须使用哪种计数方式的说法。
二、进制的转换及其应用场景
就和现实世界中,人类存在着N种不同的语言,而使用不同语言的人要想交流就必须有翻译一样,要想进行不同进制间的数据的计算,首先就必须要对数据统一进行数据进制的转换。这样,不同进制间的数据进行运算才能得到正确的结果。
对二进制和十六进制的转换来说,是比较简单的,毕竟本质他们是一样的。麻烦的在于,它们二者与十进制的互相转换,这个稍微有一些复杂,不过也只是形式上有些复杂。毕竟进制的转换本质都是类似的。其具体的应用场景如下:
- 二进制
二进制的应用在计算机中是非常广泛的,比如常见的位操作、图像的像素处理、文件的二进制读写以及网络传送中的二进制流等等。换句话说,计算机中,离不开二进制。 - 八进制
八进制在现代的计算机中基本很少应用了,当然,现实世界就更不用想了。不过,在早期的计算机中,八进制还是用得相当锪。目前比较容易接触到的八进制处理应用可能就是类Unix下的文件权限描述。 - 十进制
十进制在计算机世界中应用也很多,比如与用户交互的输入输出、现实世界的数据计算等,也就是说,方便与现实世界交互的进制还是得用十进制。 - 十六进制
十六进制在计算机世界中就应用相当广泛了,在上层应用中,为了方便开发者更好的与计算机交互,如内存的处理、颜色的描述以及数据的转换等,十六进制就更有优势。
其实在加密处理、数据通信特别是与硬件交互的场景下,二进制和十六进制应用的都非常的广泛,有过开发经验的可能一看就明白了,勿需赘述。
另外一个需要重点提示的,在C/C++的实际应用中,进制的转换往往意味着数据类型的转换,这就需要开发者一定要小心有无符号、是否超范围溢出等等特殊情况的处理。如果不小心处理的话,往往会导致数据处理结果的异常。如在处理图像数据时,可能最终显示的结果与预测的不同。
三、C++进制的转换及显示
对C++来说,进制的转换应用有很多种,但常用的主要有两大类:
- 进制的转换
这种转换有很多种方法,可以自己手写一套相关的转换方法,但对大多数人来说,如果有相关的库可以用那就是最好不过的了。在C++中主要的方法有:
- 按照进制间的转换规则手动实现相关的进制数据转换(比如十进制转八或十六进制可以使用除余法或转成二进制再转的方法),当然也可以直接进行位操作来实现
- 使用STL流(std::cin,std::stringstream等)的std::hex,std::oct,std::dec(标准中称为manipulators,操纵器)
- 二进制的处理可以使用std::bitset(C++11)相关接口,包二进制与其它进制的转换
- 可以使用sscanf函数和sprintf函数来处理一些二进制数据、十进制数据及十六进制数据的处理
- 不同进制的数据显示
- 使用STL的输出流(std::cout),使用std::hex,std::oct,std::dec参数控制
- 使用C库中的printf相关的格式参数%x,%o,%d等,注意十六进制的%x有大小写
- 复杂的显示可以sscanf函数和sprintf函数处理后再进行显示
另外,此处比较麻烦的是进行小数和有符号的进制转换时比较麻烦,再次提醒一下。
四、例程
根据上面的分析,下面写几个例子来实现一下进制的转换:
#include <bitset>
#include <cstdio>
#include <iostream>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
std::string dec2hex(unsigned long d) {
if (d == 0) {
return "0";
}
std::string hex;
const char hexAll[] = "0123456789ABCDEF";
while (d > 0) {
int pos = d & 0xF;
hex = hexAll[pos] + hex;
d >>= 4;
}
return hex;
}
void testBitTransfer(int d) {
std::string hex = dec2hex(d);
std::cout << "decimal: " << d << " to hex: " << hex << std::endl;
}
void sscanfAndsprintf() {
char hStr[] = "1C2E";
unsigned int n;
sscanf(hStr, "%x", &n);
printf("%s to decimal: %u\n", hStr, n);
char buf[20];
unsigned int v = 6789;
sprintf(buf, "%x", v);
printf("%u to hex: %s\n", v, buf);
char preHex[] = "0x3F";
sscanf(preHex, "0x%x", &n);
printf("prefix %s to hex: %u\n", preHex, n);
}
void printBit(int n) {
if (n > 1) {
printBit(n / 2);
}
std::cout << "recursion printf bits:" << n % 2 << std::endl;
}
void printBinary(int n) {
for (int i = 31; i >= 0; i--) {
std::cout << ((n >> i) & 1);
}
std::cout << std::endl;
std::cout << "binary: " << std::bitset<32>(n) << std::endl;
}
void testB2Other() {
std::string bStr = "111010";
std::bitset<32> bBitset(bStr);
// binary 2 decimal
unsigned long dNum = bBitset.to_ulong();
std::cout << "Decimal: " << dNum << std::endl;
std::stringstream hss;
// 2 hex
hss << std::hex << dNum;
std::string hStr = hss.str();
std::cout << "Hex: " << hStr << std::endl;
}
void testHex2Other() {
std::string hStr = "3D";
int dNum;
// Hex to Decimal
std::istringstream(hStr) >> std::hex >> dNum;
std::cout << "decimal:" << dNum << std::endl;
// Decimal to Octal
std::stringstream oSs;
oSs << std::oct << dNum;
std::string oStr = oSs.str();
std::cout << "Octal : " << oStr << std::endl;
}
int main() {
int hexData = 0;
std::cin >> std::hex >> hexData;
testHex2Other();
testB2Other();
sscanfAndsprintf();
testBitTransfer(100);
printBinary(58);
printBit(58);
return 0;
}
代码比较简单,大家如果有更好的方法可以提出来一起分享。
五、总结
进制其实就和人们对待同样的事物,不同的地点有不同的处理方式一样。比较容易理解的就是度量衡,中国古代使用十六两一斤的方法描述重量,欧美使用磅。如果双方要进行贸易,首先得进行一下进制的转换,才能保证交易的正常进行。
进制虽然简单,但是在很多情况下,被大家不经意的疏忽,导致在计算过程中出现一些意想不到的问题。还是需要在应用时,提高警惕。

4万+

被折叠的 条评论
为什么被折叠?



