为什么变量名不能以数字开头?


136

当我问一个问题:“为什么变量名不能以数字开头?”时,我正与一个新的C ++开发人员一起工作。

除了一些数字可以包含文本(123456L,123456U)外,我无法给出答案,并且如果编译器认为带有一定数量的字母字符的所有内容都是变量名,那将是不可能的。

那是正确的答案吗?还有其他原因吗?

string 2BeOrNot2Be = "that is the question"; // Why won't this compile?

15
他们为什么不能在其中留空间?
蒂姆(Tim)

4
这个问题比C ++早了至少20年,甚至还没有追溯到第一个宏汇编程序之前。
Ken Gentle

2
好吧,在FORTH中,您可以做到。AFAIK,有一个叫00 的单词被压入堆栈。另一个是0=检查堆栈上是否为0。
Ingo

12
为什么这个问题如此受欢迎而答案却如此错误?许多语言都允许变量以数字开头。C ++并非如此,但这只是一个方便的限制,可以避免某些歧义。有时SO会以所有错误的方式使我惊讶。
david.pfx 2014年

5
如果今天就SO提出此问题,则将其称为基于意见的解决方案。感谢您的询问。
Boon 2015年

Answers:


116

因为那样一串数字将是一个有效的标识符以及一个有效的数字。

int 17 = 497;
int 42 = 6 * 9;
String 1111 = "Totally text";

37
好吧,如果他们说变量不能只是数字。那呢
Pyrolistical

6
如果可能的话,我需要花更长的时间为词法分析器提供一个正则表达式来使用该规则来选择标识符,因此,我可以看到为什么除了以其他答案。
skiphoppy

39
如果必须是数字+ alpha,那么您仍然可以执行String 0x123 =“ Hello World”。除非您声明变量名称是“数字+字母,但不能解析为有效的数字名称”,否则这很愚蠢。
eaolson

4
不用担心编译器:使用该语言的人们需要能够(一眼)将变量名与数字区分开。如果第一个字符没有告诉您-相反,如果您需要搜索单词的其余部分以判断其中是否存在非数字字母-代码将更难阅读。
即将到来的暴风雨2012年

10
@eaolson:我与一个汇编程序一起工作,该汇编程序将该规则应用于以A- 开头F并以结束的十六进制数字h。第一次让我绊倒的时候,我试图定义一个标签来指向巴赫的《两部分发明》(13 Bach)的音乐数据(逻辑名称? )。
2012年

116

好考虑一下:

int 2d = 42;
double a = 2d;

什么啊 2.0?还是42?

提示,如果不明白,数字后的d表示它是双精度字面量之前的数字


11
实际上,这是[相对]较晚的表示法(“ d”表示“ double”),C89标准IIRC。如果此构造使用语言,则不可能在标识符中使用前导数字,但这不是数字无法启动标识符的原因。
Ken Gentle

1
d在C ++中不是有效的浮动文字后缀。默认情况下,浮点文字为双精度型,您可以使用,f或者l如果需要浮点数或长双精度型文字,则可以使用。
CB Bailey

1
它是针对Java的,而最初的问题是针对C ++的,它也适用于许多其他语言,例如Java。但我同意。这不是标识符不能以数字开头的原始原因。
Pyrolistical

50

现在这是一个惯例,但它最初是一项技术要求。

在过去,诸如FORTRAN或BASIC之类的语言的解析器不需要使用空格。因此,基本上,以下内容是相同的:

10 V1=100
20 PRINT V1

10V1=100
20PRINTV1

现在假设允许使用数字前缀。您将如何解释?

101V=100

10 1V = 100

或作为

101 V = 100

或作为

1 01V = 100

因此,这被定为非法。


1
次要的:行号必须在1-6列中,而可执行代码必须在第8列之后。另一方面DO 10 I=1,50DO1 0I=1,50[ 可能会使用句号而不是逗号来进行歧义地解析,该语句成为对a的赋值。名为的浮点变量DO10I
2012年

有趣的解释!这是有道理的,旧的语言,还是让我不知道为什么我们仍然延续了设计的选择。像Python或JavaScript或R语言
查尔斯·克莱顿

我绝对记得使用BASIC进行此操作,并认为这可能是该实践中最有效的实践原因。从技术上讲,我隐约记得它实际上可以追溯到早期的汇编语言。我不确定是什么汇编程序,我很可能是错的。
布赖恩·钱德勒

42

因为在编译时在词法分析中避免了回溯。像这样的变量:

Apple;

编译器在遇到字母“ A”时会立即知道它是一个标识符。

但是像这样的变量:

123apple;

编译器在命中“ a”之前将​​无法确定它是数字还是标识符,因此需要回溯。


2
要想起我的编译器设计类来回答问题,这个答案就对了!荣誉
nehem

15

编译器/解析器/词法分析器对我来说是很久以前的事,但我想我记得很难明确地确定编译单元中的数字字符是文字​​还是标识符。

由于这种原因,空格很小的语言(例如ALGOL和原始的FORTRAN,如果我没记错的话)不能接受数字作为标识符的开头。

这可以追溯到-在特殊符号表示存储或数字基数之前。


9

我同意允许标识符以数字开头很方便。一两个人提到,您可以通过在标识符前加下划线来解决此限制,但这确实很丑陋。

我认为部分问题来自数字文字,例如0xdeadbeef,这使得很难想出容易记住的以数字开头的标识符规则。一种方法是允许与[A-Za-z _] +匹配的任何内容,而不是关键字或数字文字。问题在于,这将导致允许使用0xdeadpork之类的怪异事物,但不允许使用0xdeadbeef。最终,我认为我们应该对所有肉类都公平:P。

当我第一次学习C时,我记得感觉变量名的规则是任意的和限制性的。最糟糕的是,它们很难记住,所以我放弃了学习它们的尝试。我只是做了感觉正确的事情,并且效果很好。现在,我学到了很多东西,似乎还不错,我终于开始正确地学习它了。


8
大声笑-“问题在于,这将导致允许使用0xdeadpork之类的怪异事物,但不允许使用0xdeadbeef。最终,我认为我们应该对所有肉类都公平:P。”
mr-euro

6

做出此决定的原因可能很多种,当您解析令牌时,只需查看第一个字符即可确定它是标识符还是文字,然后将其发送给正确的函数进行处理。这就是性能优化。

另一种选择是检查它是否不是文字,并将标识符的域保留为Universe减去文字。但是要做到这一点,您将必须检查每个标记的每个字符以知道如何对其进行分类。

还有标识符的风格含义,它们应该是助记符,因此单词比数字更容易记住。当编写许多原始语言来设置接下来几十年的样式时,他们没有考虑将“ 2”替换为“ to”。


6

变量名不能以数字开头,因为它可能引起如下问题:

int a = 2;
int 2 = 5;
int c = 2 * a; 

c的值是多少?是4,还是10!

另一个例子:

float 5 = 25;
float b = 5.5;

是前5个数字,还是一个对象(。运算符),后5个存在类似的问题。

也许还有其他原因。因此,我们不应在变量名的开头使用任何数字。


即使要求标识符至少包含一个非数字字符,也必须要求包含字母的数字格式还必须包含非字母数字字符(例如要求将0x1234写入$ 1234和1E6写入)例如[1.E6或1.0E6],否则合法和非法标识符名称的组合应为奇数。
超级猫

4

使用数字开头的变量名会使编译或插入过程中的错误检查变得更加复杂。

允许使用以数字开头的变量名可能会给语言设计人员带来巨大的问题。在源代码解析期间,每当编译器/解释器遇到一个以数字开头的标记(该数字应为变量名)时,它都必须搜索大量复杂的规则,以确定该标记是真正的变量还是错误。 。语言分析器增加的复杂性可能无法证明此功能的合理性。

据我所记得(大约40年),我不认为我曾经使用过一种允许使用数字来开头变量名的语言。我确信这至少完成了一次。也许,这里的某个人实际上已经在某处看到了这个。


1
没那么难。仅此而已,这使得词法阶段更加困难。当然,当我使用编译器时,有人告诉我词法扫描可能会占用总编译时间的四分之一。
David Thornley,2009年

4

正如一些人所注意到的,关于变量名的有效格式有很多历史包bag。语言设计师在创建新语言时总是会受到他们所知道的知识的影响。

就是说,一种语言几乎所有时间都不允许变量名以数字开头是因为这是语言设计的规则。通常是因为这样简单的规则使语言的解析和词法化变得非常容易。但是,并非所有的语言设计师都知道这是真正的原因。现代的词法分析工具会有所帮助,因为如果您尝试将其定义为允许的,它们将为您解析冲突。

OTOH,如果您的语言在预示变量名称中具有唯一可识别的字符,则可以将其设置为以数字开头。类似的规则变体也可以用于在变量名中保留空格。但是,最终的语言可能根本不会与任何流行的常规语言非常相似。

有关一个相当简单的HTML模板语言的示例,该语言确实允许变量以数字开头并具有嵌入的空格,请参见Qompose


1
实际上,有几种语言允许您使用字符来标识标识符。它们被称为“签名”,而您在Perl和PHP中拥有它们。
杰森·贝克

除非您仍然不允许在PHP中使用数字开头变量名-语言规则禁止使用它。:-)但是出于完全相同的原因,您可以在Qompose中使用。
staticsan

4

因为如果您允许关键字和标识符以数字字符开头,那么词法分析器(编译器的一部分)将无法轻易地区分数字文字和关键字的开头,而不会变得更加复杂(也更慢)。


2
词汇化过程很少成为瓶颈。当然,这会使标识符令牌的正则表达式更加复杂,但它们仍可以是超快速DFA。与编译器必须完成的大多数其他任务相比,这些代码的运行时间是小菜一碟。



2

C ++无法拥有它,因为语言设计者已将其作为规则。如果要创建自己的语言,当然可以允许它,但是您可能会遇到他们遇到的相同问题,并决定不允许它。可能引起问题的变量名示例:

0x,2d,5555


这种限制适用于不允许使用这种语法的语言。
杰森·贝克

2

放松语法约定的关键问题之一是将认知失调引入了编码过程。您对代码的看法可能会因缺乏清晰性而受到深深影响。

迪克斯特拉不是在说“任何工具的最重要方面就是对用户的影响”吗?


1

可能是因为它使人更容易分辨它是数字还是标识符,并且是由于传统。具有可以以数字开头的标识符不会使词汇扫描变得十分复杂。

并非所有语言都禁止以数字开头的标识符。在Forth中,它们可以是数字,并且通常将小整数定义为Forth单词(基本上是标识符),因为将“ 2”作为将2压入堆栈的例程比将“ 2”识别为数字要快得多其值是2。(在处理来自程序员或磁盘块的输入时,Forth系统将根据空格对输入进行拆分。它将尝试在字典中向上查找令牌以查看其是否为已定义的单词,以及如果不是,则尝试将其转换为数字,否则,将标记错误。)


问题是,Forth确实没有非常复杂的解析器。确实,它关心的只是标识符是否在两组空白之间。
杰森·贝克

1

假设您确实允许符号名称以数字开头。现在假设您要命名一个变量12345foobar。您如何将其与12345区别开?使用正则表达式实际上并不困难。问题实际上是性能之一。我无法真正解释为什么会如此详细,但实际上可以归结为以下事实:区分12345foobar和12345需要回溯。这使得正则表达式不确定。

有这样一个更好的解释这里


1
如何设计正则表达式以允许名为ifqor或doubleznot ifor 的变量double?允许标识符以数字开头的基本问题是,现有形式的十六进制文字和浮点数完全由字母数字字符组成(语言将使用$ 1234或h'1234之类的东西,而不是0x1234,并要求使用数字1E23包含一个期限,可以避免该问题)。请注意,正则表达式解析C的尝试已经被诸如之类的事情绊倒了0x12E+5
2012年

1

编译器很容易在内存位置而不是数字上使用ASCII标识变量。


1

编译器具有7个阶段,如下所示:

  1. 词法分析
  2. 语法分析
  3. 语义分析
  4. 中间代码生成
  5. 代码优化
  6. 代码生成
  7. 符号表

在词法分析阶段,在编译代码时避免回溯。像Apple这样的变量,在词法分析阶段遇到字母'A'字符时,编译器会立即知道其标识符。但是,对于像123apple这样的变量,编译器在命中“ a”之前将​​无法确定其数字还是标识符,并且需要回溯到词法分析阶段才能确定它是变量。但是编译器不支持它。

解析令牌时,只需查看第一个字符即可确定它是标识符还是文字,然后将其发送到正确的函数进行处理。这就是性能优化。


0

我认为简单的答案是可以,限制是基于语言的。在C ++和许多其他语言中,它不能,因为该语言不支持它。它没有内置在规则中以允许这样做。

问题类似于问国王为什么不能一次在国际象棋中移动四个空格?这是因为在国际象棋中这是非法的举动。可以在其他游戏中确定吗。它仅取决于所遵循的规则。


除了C ++是还活着的人最近发明的。我们可以问他们为什么选择他们所做的事情,而拒绝其他选择。同样不适用于国际象棋。
史蒂夫·杰索普

但这不是我要讲的重点。这比喻为什么变量名开头不能有数字,最简单的答案是,因为语言规则不允许这样做。
kemiller2002

可以,但是我不认为发问者是不礼貌的。他自己可能已经解决了那么远。IMO问题是“为什么语言规则不允许?”。他想弥合了解规则和理解规则之间的鸿沟。
史蒂夫·杰索普

是的,考虑到这一点,我意识到了你要去的地方。你有一定道理。我猜想我是在自由地使用Occam的剃须刀,并认为除了变量不是以数字开头(因为没有数字)之外,没有真正的答案。
kemiller2002

我并不是说您是错的,介意的是,C ++标准组织的决策有时会超越世俗的理解,而您最终会“因为他们必须做出决定,而他们决定了这一点”。但是至少有一个问题要问:-)
史蒂夫·杰索普

0

最初只是因为它容易记住(可以赋予它更多的含义)变量名而不是数字(虽然可以在字符串中包含数字以增强字符串的含义或允许使用相同的变量名),而不是数字。将其指定为具有单独但紧密的含义或上下文。例如loop1,loop2等将始终让您知道您处于循环中和/或循环2是loop1中的循环。您更喜欢哪个(更有意义)作为变量:address或1121298?哪个更容易记住?但是,如果该语言使用的东西不仅表示文本或数字(例如$ address中的$),它实际上不应该有所作为,因为这将告诉编译器以下内容将被视为变量(在这种情况下)。


0

编译器在编译期间也可以将该变量视为一个值,因此该值可以一次又一次地递归调用该值。


0

在词法分析阶段编译代码时避免回溯。像苹果这样的变量;,编译器在词法分析阶段遇到字母“ A”字符时,将立即知道其标识符。但是,变量如123apple; ,编译器在命中“ a”之前将​​无法确定其数字还是标识符,并且需要回溯以进入词法分析阶段以识别它是变量。但是编译器不支持。

参考


0

声明变量可能没有什么问题,但是尝试在其他地方使用该变量时存在一些歧义:

让1 =“世界你好!” 打印(1)打印(1)

print是接受所有类型变量的通用方法。因此在这种情况下,编译器不知道程序员(1)指的是:整数值1还是存储字符串值的1。在这种情况下,对于编译器而言,允许定义类似的内容可能会更好,但是在尝试使用这些含糊不清的内容时,请带一个带有纠正功能的错误以解决该错误并清除歧义。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.