为什么要使用十六进制?

63

嘿!我在http://www.gnu.org/software/m68hc11/examples/primes_8c-source.html上看到了这段代码。

我注意到在某些情况下,他们使用了十六进制数字,就像在第134行中:

for (j = 1; val && j <= 0x80; j <<= 1, q++)

那么为什么他们要使用0x80呢?我并不太擅长于十六进制,但我找到一个在线的十六进制转十进制工具,它告诉我0x80等于128。

还有,在第134行之前,在第114行,他们有这个:

small_n = (n & 0xffff0000) == 0;

这个十六进制数转十进制后为4294901760。在这一行中,他们进行位与运算并将结果与0比较?

为什么不直接使用这个数字呢? 能否解释一下,并给出其他情况的示例。

我也看到过很多只有十六进制数字的大段代码,从未真正理解为什么要这样做 :(

12个回答

106
在您提到的两种情况中,数字的二进制模式很重要,而不是实际的数字。
例如,在第一种情况下,随着循环的进行,变量j将依次为1、2、4、8、16、32、64和最终的128。
以二进制表示如下: 0000:00010000:00100000:01000000:10000001:00000010:00000100:00001000:0000
在C语言(直至C23)或C ++语言(直至C++14)中没有二进制常量的选项,但在十六进制中更清晰: 0x010x020x040x080x100x200x400x80
在第二个例子中,目标是去除值的较低两个字节。 因此,给定值1,234,567,890我们想要得到1,234,567,168。
用十六进制表示更清晰:从0x4996:02d2开始,最终变为0x4996:0000

2
第二个例子有一个小修正:它移除了四字节数字的低两个字节。移除低四个字节只需要“small_n = 0;”。 - Dave Sherohman
3
哎呀!你知道的,我在考虑是写“4位数”还是“两个字节”,所以自然而然地混淆了它们,导致说错了话...... - James Curran

19

这是一个位掩码。十六进制值使得底层的二进制表示更易于被看清楚。n & 0xffff0000 返回 n 的前16位。0xffff0000 表示 "在二进制中有16个1和16个0"。

0x80 表示"10000000",所以你从"00000001"开始,继续将该位向左移动"0000010","0000100"等,直到"1000000"。


19

十六进制(或八进制)数字与底层位模式存在直接映射关系,这在十进制中并不是这样。对于位模式,十进制中的“9”表示的含义取决于它所在的列和周围的数字——它没有直接与位模式的关系。在十六进制中,“9”始终表示“1001”,无论它在哪一列。例如,9 = '1001',95 = '*1001*0101'等。

作为我8位时代的残余,我发现十六进制是表示任何二进制数的方便简写方式。位运算技能正在逐渐消失。大约10年前,我看到了一篇第三年的网络论文,班上只有10%(50人左右中的5人)能计算位掩码。


16

0xffff0000 很容易理解,它是一个32位值中16个"1"和16个"0"相乘的结果,而4294901760则是神奇的数字。


11

我觉得很烦恼的是,C语言家族一直支持八进制和十六进制,但不支持二进制。我一直希望他们能够直接支持二进制:

int mask = 0b00001111;

许多年前/工作时,我在处理一个涉及大量位级数学的项目时感到厌烦,并生成了一个头文件,其中包含了所有可能的8位二进制值的定义常量:

#define b0        (0x00)
#define b1        (0x01)
#define b00       (0x00)
#define b01       (0x01)
#define b10       (0x02)
#define b11       (0x03)
#define b000      (0x00)
#define b001      (0x01)
...
#define b11111110 (0xFE)
#define b11111111 (0xFF)

有时它可以使某些位级代码更易读。


3
有些编译器会作为扩展实现直接支持二进制,比如一些 PIC C 编译器,通常会用类似于 “0b10110110” 的语法。 - nobody
1
@Andrew Medico,你得到了你想要的C++14,它完全符合你所提到的形式。 - Jesper Juhl

7

十六进制最大的用途可能就是在嵌入式编程中。十六进制数字被用来屏蔽硬件寄存器中的单个位,或将多个数字值分割成一个8、16或32位的寄存器。

当指定单个位掩码时,很多人会开始使用:

#define bit_0 1
#define bit_1 2
#define bit_2 4
#define bit_3 8
#define bit_4 16
etc...

一段时间后,他们进阶到:
#define bit_0 0x01
#define bit_1 0x02
#define bit_2 0x04
#define bit_3 0x08
#define bit_4 0x10
etc...

然后他们学会了作弊,让编译器在编译时优化时生成值:

#define bit_0 (1<<0)
#define bit_1 (1<<1)
#define bit_2 (1<<2)
#define bit_3 (1<<3)
#define bit_4 (1<<4)
etc...

6

通常使用十六进制数而不是十进制数,因为计算机使用位(二进制数),当你使用位时,使用十六进制数更容易理解,因为从十六进制到二进制比从十进制到二进制更容易。

OxFF = 1111 1111 ( F = 1111 )

但是
255 = 1111 1111 

因为

255 / 2 = 127 (rest 1)
127 / 2 = 63 (rest 1)
63 / 2 = 31 (rest 1)
... etc

你能看到吗?从十六进制转换成二进制更加简单。


6
有时,使用十六进制的可视化值可以使代码更易读或理解。例如,在查看数字的十进制表示时,位掩码或位使用变得不明显。
这可能与特定值类型所提供的空间量有关,因此这也可能起到作用。
一个典型的例子可能是在二进制设置中,因此我们使用二进制来显示一些值,而不是使用十进制。
假设一个对象具有一组非排他性属性,这些属性的值为开或关(其中有3个)- 表示这些属性的状态的一种方法是使用3位。
有效的表示方式是十进制的0到7,但这并不明显。更明显的是二进制表示法:
000、001、010、011、100、101、110、111
另外,有些人对十六进制非常熟悉。还要注意,硬编码的魔数就是那样,使用哪种编号系统并不是很重要。
希望这有所帮助。

4

十六进制数(Hexadecimal)是IT技术中常用的数字表示方式,每个数代表4位数据,从0到15或者在HEX中是0到F。两个十六进制数可以组成一个字节。


4
一个字节有8位。十六进制,也称为基数16,是一种简洁的表示方法。每个可能的字节值都用从0到9的两个字符加上a,b,c,d,e,f中的一个来表示。
基数256会更加简洁。每个可能的字节都可以拥有自己的单个字符,但大多数人类语言不使用256个字符,因此十六进制是胜利者。
要理解简洁的重要性,请考虑回到1970年代,当您想要检查您的1兆字节内存时,它是以十六进制打印出来的。打印输出将使用几千页纸张。八进制将浪费更多的树木。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接