为什么十六进制数要以0x开头?

545
为什么十六进制数要以前缀0x开头? 我了解前缀的用法,但我不明白为什么选择0x

12
现在我意识到标题和正文提出了两个完全不同的问题。大多数回复都集中在标题上的问题上。对于正文中的问题,答案很简单:“它没有任何意义——它仅仅是一个前缀,告诉编译器这个整数是用十六进制写的。” - Andreas Rejbrand
35
严谨来说,题目中的问题可以有两种不同的解释方式:1)“为什么十六进制数要以0x作为前缀,而不是其他任何前缀或指示符?”2)“为什么我们需要在输入十六进制数时使用前缀?毕竟编译器即使没有前缀也能识别58A为十六进制数。”对于第二个问题的答案是显而易见的。“123”也是一个十六进制数。 - Andreas Rejbrand
4
为什么前缀0x表示十六进制数,而不是0h? - DawnSong
5个回答

571

简短故事: 在编程中,数字前的0表示常量(不是标识符/保留字)。还需要指定数字进制:使用x是任意选择。

长故事: 在六十年代,流行的编程数字系统是十进制和八进制——大型计算机每个字节有12、24或36位,这可以被3 = log2(8)很好地整除。

BCPL语言使用8 1234语法来表示八进制数字。当Ken Thompson从BCPL创建出B语言时,他使用了0前缀。这很好,因为

  1. 整数常量现在始终由单个令牌组成,
  2. 解析器仍然可以立即确定它已经获得了一个常量,
  3. 解析器可以立即确定基数(0在两种基数中相同),
  4. 它在数学上是合理的(00005 == 05),并且
  5. 不需要珍贵的特殊字符(如#123)。

当C从B创建时,需要十六进制数字(PDP-11具有16位字)。所有上述点仍然有效。由于其他机器仍需要八进制,因此任意选择了0x(可能排除了00,因为它很尴尬)。

C#是C的后代,因此继承了该语法。


142
我认为0x相对于00不是偏好或笨拙之举。00会破坏现有的代码。八进制数0010等于十进制的8,而十六进制数0010则等于16。他们不能使用任何数字作为第二位指示符(除了89,但它们与十六进制没有任何相关意义),所以字母是必须的。这留下了要么是0h要么是0xH e X十六进制)。从这一点上看,似乎真的回到了个人喜好的问题。 - GManNickG
2
相关链接:https://dev59.com/fXfZa4cB1Zd3GeqPOzdd 和 https://dev59.com/8Ggu5IYBdhLWcg3wOUm- - Řrřola
32
多年来,在八进制前使用“0”前缀引起了很多问题,尤其是在像英国这样以“0”开头的电话号码的国家。JavaScript和许多其他语言会将它们解析为八进制,导致存储前修改数字的值。更有趣的是,一款流行的数据库产品如果数字包含“8”或“9”则会悄悄地切换回十进制解析。 - Basic
5
可能是因为十六进制并不是很相关。那个时候大部分的硬件、软件和文档都更适合使用八进制。BCPL最初是在一台36位IBM 7094上实现的,指令格式分成了两个3位部分和两个15位部分;字符长度为6位;文档以八进制形式记录。B语言早期的实现是在一台PDP-7(18位)和一台Honeywell GE-945(36位,但只有18位寻址,并支持6位和9位字节)上完成的。16位的PDP-11是在B语言之后推出的,因此不会对B语言的设计产生太大影响。 - 8bittree
1
你是什么意思说“解析器可以立即确定基数(0在两个基数中都相同)。”如果八进制和十进制中的0是相同的...那你怎么能确定基数呢? - Jwan622
显示剩余8条评论

118

注意:我不知道正确答案,但以下仅是我的个人猜测!

如前所述,数字前的0表示八进制:

04524 // octal, leading 0

假设你需要设计一个表示十六进制数字的系统,且我们正在使用类似于C语言的环境。那么像汇编一样以h结尾呢?不幸的是,你不能这样做 - 这将允许你创建有效标识符的令牌(例如,你可以给变量命名相同的名称),这会导致一些恶意的歧义。

8000h // hex
FF00h // oops - valid identifier!  Hex or a variable or type named FF00h?

你不能以一个字符开头,原因也是相同的:

xFF00 // also valid identifier

使用哈希可能被排除是因为它与预处理器冲突:

#define ...
#FF00 // invalid preprocessor token?

最终,出于某种原因,他们决定在十六进制数前面加一个 0x。这是一种无歧义的表示方式,因为它仍然以数字字符开头,因此不能作为有效的标识符,这可能是基于八进制约定的延续。

0xFF00 // definitely not an identifier!

6
有趣。我想他们本可以使用前导0和尾随h来表示十六进制。但是,尾随的h可能会与类型后缀混淆,例如0xFF00l与0FF00hl。 - zdan
3
这个论点暗示了在八进制数字中使用前导零的做法早于使用十六进制的“0x”前缀。这是真的吗? - Andreas Rejbrand
1
它们不是同时发明的吗?为什么会有一个而没有另一个呢? - AshleysBrain
1
AshleysBrain看到了@Řrřola的回答,解释了为什么可能同时存在八进制但不存在十六进制。 - jv42
3
@zdan 他们很久以前就使用过它了。在x86 Intel汇编中,十六进制字面量必须始终以0为前缀,如果它们以字符开头。例如,0xFFAB1234必须写成0FFAB1234h。我还记得我年轻时在Pascal的内联汇编中使用它。https://dev59.com/VGgt5IYBdhLWcg3w5xc_ - phuclv
显示剩余2条评论

40

这是一个前缀,用于指示数字是十六进制而不是其他进制。编程语言使用它来告诉编译器。

例子:

0x6400 翻译成 6*16^3 + 4*16^2 + 0*16^1 +0*16^0 = 25600. 当编译器读取 0x6400 时,它会在 0x 帮助下理解数字是十六进制的。通常我们可以通过 (6400)16 或 (6400)8 来理解 ..

对于二进制

0b00000001

祝您好运!


3
自C++14起,二进制字面量仅在C++中得到支持,而在C语言中则不支持。 - Ruslan
7
这并没有解释为什么。特别是,为什么不能将第一个例子写成“x6400”? “x”仍然可以用来推断十六进制。 - Aaron Franke

20

在二进制、八进制或十六进制中,前置的0用于表示数字。

我个人认为,0x被选择用于表示十六进制是因为'x'听起来像十六进制。

这只是我的看法,但我认为这是有道理的。

祝好!


3
感谢您的回答!我了解这是您在StackOverflow上的第一篇帖子。如果将观点与事实分开,答案可能会更有帮助。 - vivek_ganesan
5
这个回答很好地区分了观点和事实。 - anatolyg
我很欣赏“x”与“hex”押韵的非常合理的想法,这是一种常用的表示十六进制数字的方式。这是唯一提到它的答案。 - Douglas Held

13
我不知道为什么在十六进制数前添加0x的历史原因,因为它可能采用了许多形式。这种特定的前缀样式来自计算机科学的早期阶段。
由于我们习惯于使用十进制数,通常不需要指示基数/进制。但是,出于编程目的,我们经常需要区分二进制(基数2)、八进制(基数8)、十进制(基数10)和十六进制(基数16)- 最常用的数字基数。
此时,它是一种表示数字进制的约定。我已经在所有以上进制下使用了带有前缀的数字29:
  • 0b11101:二进制
  • 0o35:八进制,用o表示
  • 0d29:十进制,这很不寻常,因为我们默认没有前缀的数字是十进制
  • 0x1D:十六进制
基本上,我们最常与基数相关联的字母(例如二进制的b)与0相结合,以轻松区分数字的基数。
这尤其有助于较小的数字可能在所有基数中看起来混淆无比的情况:0b1、0o1、0d1、0x1。
但是,如果您使用富文本编辑器,则可以使用下标表示基数:12、18、110、116

2
为什么十六进制中不选择0h?0x看起来很奇怪。 - DawnSong
2
@DawnSong 这只是一个相当流行的惯例,现在我们必须接受它。有时这些事情是任意的。你可以尝试推广你的方法,但改变如此多人的习惯是很难的。我发现八进制的方式在视觉上最令人困惑。 - Advait Junnarkar

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