为啥使用十六进制?
Posted
技术标签:
【中文标题】为啥使用十六进制?【英文标题】:Why use hex?为什么使用十六进制? 【发布时间】:2010-09-19 14:42:19 【问题描述】:嘿!我在http://www.gnu.org/software/m68hc11/examples/primes_8c-source.html查看这段代码
我注意到在某些情况下他们使用十六进制数字,例如第 134 行:
for (j = 1; val && j <= 0x80; j <<= 1, q++)
现在他们为什么要使用 0x80?我对十六进制不太擅长,但我发现了一个在线十六进制到十进制,它给了我 128 的 0x80。
同样在第 134 行之前,在第 114 行他们有这个:
small_n = (n & 0xffff0000) == 0;
十六进制到十进制给了我 4294901760 的十六进制数。 所以在这一行中,他们做了一点 AND 并将结果与 0 进行比较??
为什么不直接使用数字呢? 任何人都可以解释一下,并请给出其他情况的例子。
我也见过大行代码,其中只是十六进制数字,但从未真正理解为什么:(
【问题讨论】:
【参考方案1】:在您引用的两种情况下,数字的位模式都很重要,而不是实际数字。
例如,
在第一种情况下,
随着循环的进行,j
将是 1,然后是 2、4、8、16、32、64,最后是 128。
二进制,即
0000:0001
、0000:0010
、0000:0100
、0000:1000
、0001:0000
、0010:0000
、0100:0000
和 1000:0000
。
在 C(C23 之前)或 C++(C++14 之前)中没有二进制常量的选项,但在 Hex 中更清晰一些:
0x01
、0x02
、0x04
、0x08
、0x10
、0x20
、0x40
、0x80
。
在第二个例子中,
目标是删除值的低两个字节。
所以给定 1,234,567,890 的值,我们希望最终得到 1,234,567,168。
十六进制更清晰:以0x4996:02d2
开头,以0x4996:0000
结尾。
【讨论】:
第二个例子的小修正:它删除了一个四字节数字的低两个字节。删除低四个字节就是“small_n = 0;”。 哦!你知道,我在写“4位”和“两个字节”之间争论不休,所以我很自然地将它们混为一谈……【参考方案2】:它是一个位掩码。十六进制值使查看底层二进制表示变得容易。 n & 0xffff0000
返回 n 的前 16 位。 0xffff0000
表示“二进制中的 16 个 1 和 16 个 0”
0x80
表示“1000000”,因此您从“00000001”开始并继续将该位向左移动“0000010”、“0000100”等,直到“1000000”
【讨论】:
【参考方案3】:十六进制(或八进制)数字与底层位模式之间存在直接映射,而十进制则不是这种情况。十进制“9”表示位模式的不同,具体取决于它所在的列以及围绕它的数字 - 它与位模式没有直接关系。在十六进制中,“9”始终表示“1001”,无论是哪一列。 9 = '1001',95 = '*1001*0101' 等等。
作为我 8 位时代的遗迹,我发现 hex 是任何二进制文件的便捷简写。小玩意儿是一种垂死的技能。有一次(大约 10 年前)我在大学三年级的网络论文中看到,班上只有 10%(50 人中有 5 人左右)可以计算位掩码。
【讨论】:
【参考方案4】:0xffff0000 很容易理解,它是 32 位值的 16 倍“1”和 16 倍“0”,而 4294901760 是魔术。
【讨论】:
【参考方案5】: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)
它偶尔会使某些位级代码更具可读性。
【讨论】:
回复:“我一直希望他们能直接支持二进制”——一些编译器确实将其作为扩展实现:我在各种 PIC C 编译器中看到过它,通常类似于“0b10110110 " @Andrew Medico 你用 C++14 实现了你所提到的形式。【参考方案6】:十六进制的最大用途可能是在嵌入式编程中。十六进制数用于屏蔽硬件寄存器中的各个位,或将多个数值拆分为单个 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...
【讨论】:
【参考方案7】:有时,十六进制值的可视化表示使代码更具可读性或可理解性。例如,在查看数字的十进制表示时,位掩码或位的使用变得不明显。
这有时与特定值类型必须提供的空间量有关,因此这也可能起作用。
一个典型的例子可能是二进制设置,所以我们不使用十进制来显示某些值,而是使用二进制。
假设一个对象具有一组非排他性的属性,这些属性的值可以是 on 或 off(其中 3 个) - 表示这些属性状态的一种方法是使用 3 位。
有效的表示是十进制的 0 到 7,但这并不那么明显。更明显的是二进制表示:
000, 001, 010, 011, 100, 101, 110, 111
另外,有些人对十六进制非常满意。另请注意,硬编码的幻数就是这样,无论使用哪种编号系统,它都不是那么重要
希望对你有帮助。
【讨论】:
【参考方案8】:通常使用十六进制数而不是十进制数,这是因为计算机使用位(二进制数),当您使用位时使用十六进制数也更容易理解,因为从十六进制到二进制更容易十进制转二进制。
OxFF = 1111 1111 ( F = 1111 )
但是
255 = 1111 1111
因为
255 / 2 = 127 (rest 1)
127 / 2 = 63 (rest 1)
63 / 2 = 31 (rest 1)
... etc
你能看到吗?从十六进制传递到二进制要简单得多。
【讨论】:
【参考方案9】:一个字节有 8 位。十六进制,以 16 为底,很简洁。任何可能的字节值都使用集合 0..9 中的两个字符加上 a、b、c、d、e、f 来表示。
Base 256 会更简洁。每个可能的字节都可以有自己的单个字符,但大多数人类语言不使用 256 个字符,所以 Hex 是赢家。
要了解简洁的重要性,请考虑早在 1970 年代,当您想要检查您的兆字节内存时,它以十六进制打印出来。打印输出将使用数千页大纸。八进制会浪费更多的树。
【讨论】:
【参考方案10】:十六进制或十六进制数字表示 4 位数据,0 到 15 或十六进制 0 到 F。两个十六进制值代表一个字节。
【讨论】:
【参考方案11】:更准确地说,十六进制和十进制都是数字。基数(以 10、16 等为底)是一种以更清晰或更方便的方式呈现这些数字的方式。
在讨论“有多少东西”时,我们通常使用小数。当我们查看计算机上的地址或位模式时,通常首选十六进制,因为通常单个字节的含义可能很重要。
十六进制(和八进制)具有它们是 2 的幂的属性,因此它们可以很好地映射位分组。十六进制将 4 位映射到一个十六进制半字节 (0-F),因此一个字节存储在两个半字节 (00-FF) 中。八进制在数字设备 (DEC) 和其他较旧的机器上很流行,但一个八进制数字映射到三位,因此它不能很好地跨越字节边界。
总体而言,基数的选择是一种使您的编程更容易的方法 - 使用与域最匹配的那个。
【讨论】:
【参考方案12】:查看文件,这是一些非常棒的代码。希望你擅长 C 而不是将它用作教程......
当您直接在位级别或略高于位级别工作时,十六进制很有用。例如,在驱动程序上工作,您可以直接查看来自设备的位并调整结果,以便其他人可以读取连贯的结果。它是一种紧凑且易于阅读的二进制表示。
【讨论】:
该代码没有任何问题。看着那段代码,我找不到更清晰的方法来编写它而不使用 HEX。以上是关于为啥使用十六进制?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 Arduino Midi 库将十六进制 F7 读取为 0