当他问起一个问题时,我正在与一位新的C ++开发人员合作:“为什么变量名称不能以数字开头?”
我无法想出答案,除了一些数字可以包含文本(123456L,123456U),如果编译器认为所有带有一些字母字符的数字都是变量名称,那就不可能。
这是正确的答案吗?还有其他原因吗?
string 2BeOrNot2Be = "that is the question"; // Why won't this compile?
答案 0 :(得分:110)
好好想想:
int 2d = 42;
double a = 2d;
什么是? 2.0?还是42?
提示,如果你没有得到它,d之后的数字意味着它是双字面之前的数字
答案 1 :(得分:101)
因为那时一串数字将是有效的标识符以及有效的数字。
int 17 = 497;
int 42 = 6 * 9;
String 1111 = "Totally text";
答案 2 :(得分:42)
现在这是一个惯例,但它最初只是一项技术要求。
在过去,FORTRAN或BASIC等语言的解析器不需要使用空格。所以,基本上,以下是相同的:
10 V1=100
20 PRINT V1
和
10V1=100
20PRINTV1
现在假设允许使用数字前缀。你怎么解释这个?
101V=100
作为
10 1V = 100
或
101 V = 100
或
1 01V = 100
所以,这是非法的。
答案 3 :(得分:35)
因为在编译时词法分析中避免了回溯。变量如:
Apple;
编译器会在遇到字母“A”时立即知道它是一个标识符。
但是变量如:
123apple;
编译器在命中'a'之前无法确定它是否是数字或标识符,因此需要回溯。
答案 4 :(得分:13)
编译器/解析器/词法分析器很久很久以前对我来说,但我想我记得在确定编译单元中的数字字符是否代表文字或标识符方面存在困难。
空间无关紧要的语言(如果我没记错的话,就像ALGOL和原来的FORTRAN一样)因为这个原因无法接受数字来开始标识符。
这可以追溯到 - 在表示存储或数字基础的特殊符号之前。
答案 5 :(得分:7)
我同意允许标识符以数字开头是很方便的。有一两个人提到你可以通过在你的标识符前加一个下划线来解决这个限制,但这真的很难看。
我认为问题的一部分来自数字文字,例如0xdeadbeef,这使得很难想出易于记住可以以数字开头的标识符的规则。一种方法可能是允许匹配[A-Za-z _] +的任何东西不是关键字或数字文字。问题是它会导致像0xdeadpork这样的奇怪事情,但不会导致0xdeadbeef。最终,我认为我们应该对所有肉类都公平:P。
当我第一次学习C时,我记得感觉变量名称的规则是任意的和限制性的。最糟糕的是,他们很难记住,所以我放弃了尝试去学习它们。我只是做了感觉正确的事情,而且效果很好。既然我已经学到了很多东西,它似乎并不那么糟糕,我终于开始学习它了。
答案 6 :(得分:6)
由于某些原因,这可能是一个决定,当您解析令牌时,您只需要查看第一个字符以确定它是标识符还是文字,然后将其发送到正确的函数进行处理。这是性能优化。
另一种选择是检查它是不是文字,并将标识符域保留为宇宙减去文字。但要做到这一点,你必须检查每个标记的每个字符,以了解如何对其进行分类。
还有风格含义标识符应该是助记符,因此单词比数字更容易记住。当很多原始语言被编写为未来几十年的风格时,他们并没有考虑用“2”代替“to”。
答案 7 :(得分:4)
因为如果你允许关键字和标识符以数字字符开头,那么词法分析器(编译器的一部分)就不能轻易地区分数字文字的开头和关键字而不会使得更复杂(和更慢)
答案 8 :(得分:4)
COBOL允许变量以数字开头。
答案 9 :(得分:4)
变量名不能以数字开头,因为它可能会导致以下问题:
int a = 2;
int 2 = 5;
int c = 2 * a;
c的价值是多少?是4,还是10!
另一个例子:
float 5 = 25;
float b = 5.5;
首先是一个数字,或者是一个对象(。运算符) 第二个问题也有类似的问题。
也许,还有其他一些原因。因此,我们不应该在变量名的beginnig中使用任何数字。
答案 10 :(得分:4)
限制是任意的。各种Lisps允许符号名称以数字开头。
答案 11 :(得分:4)
有几个人注意到,关于变量名称的有效格式有很多历史包袱。语言设计师在创建新语言时总是会受到他们所知的影响。
那就是说,几乎所有的语言都不允许变量名从数字开始,因为那些是语言设计的规则。通常这是因为这样一个简单的规则使得语言的解析和复杂性变得更加容易。但并非所有语言设计师都知道这是真正的原因。现代lexing工具提供帮助,因为如果您尝试将其定义为允许,它们将为您提供解析冲突。
OTOH,如果您的语言具有唯一可识别的字符来表示变量名称,则可以将它设置为以数字开头。类似的规则变体也可用于允许变量名称中的空格。但是如果有的话,由此产生的语言很可能不会像任何流行的传统语言那样。
对于一个相当简单的HTML模板语言的例子,它允许变量以数字开头并具有嵌入空格,请查看Qompose。
答案 12 :(得分:4)
使用数字开始变量名称会使编译或插入过程中的错误检查变得更加复杂。
允许使用以数字开头的变量名称可能会给语言设计者带来很大的问题。在源代码解析期间,只要编译器/解释器遇到以数字开头的标记,其中变量名称是预期的,就必须搜索一组庞大而复杂的规则来确定令牌是否真的是变量,或者是错误。添加到语言分析器中的复杂性可能无法证明此功能的合理性。
早在我记忆中(大约40年),我认为我从未使用过允许使用数字来开始变量名的语言。我确信这至少做过一次。也许,这里的某个人实际上已经在某处看到了这一点。
答案 13 :(得分:2)
放松句法惯例的一个关键问题是它将认知失调引入编码过程。你如何看待你的代码可能会深深地受到这将引入的清晰度的影响。
难道Dykstra不是说“任何工具最重要的方面是它对用户的影响”吗?
答案 14 :(得分:2)
C ++无法拥有它,因为语言设计者将其作为规则。如果你要创建自己的语言,你当然可以允许它,但你可能遇到他们所做的相同的问题,并决定不允许它。可能导致问题的变量名称示例:
0x,2d,5555
答案 15 :(得分:1)
假设您确实允许符号名称以数字开头。现在假设您要为变量12345foobar命名。你如何区别于12345?使用正则表达式实际上并不是非常困难。问题实际上是表现之一。我无法真正解释为什么这是非常详细的,但它基本上归结为将12345foobar与12345区分开来需要回溯。这使正则表达式不确定。
对此here有更好的解释。
答案 16 :(得分:1)
可能是因为它让人们更容易分辨它是一个数字还是一个标识符,并且因为传统。拥有可以以数字开头的标识符不会使词法扫描复杂化。
并非所有语言都有禁止以数字开头的标识符。在Forth中,它们可以是数字,小整数通常被定义为Forth字(基本上是标识符),因为将“2”作为例程将2推入堆栈比将“2”识别为数字更快它的值为2.(在处理来自程序员或磁盘块的输入时,Forth系统会根据空格分割输入。它会尝试在字典中查找令牌以查看它是否是已定义的单词,并且如果没有尝试将其转换为数字,如果没有则会标记错误。)
答案 17 :(得分:1)
编译器很容易在内存位置使用ASCII而不是数字来识别变量。
答案 18 :(得分:0)
最初只是因为它更容易记住(你可以给它更多的含义)变量名称作为字符串而不是数字虽然数字可以包含在字符串中以增强字符串的含义或允许使用相同的字符串变量名称,但将其指定为具有单独但接近的含义或上下文。例如loop1,loop2等总是让你知道你在循环中和/或循环2是loop1中的循环。 您更喜欢(有更多意义)作为变量:地址还是1121298?哪个更容易记住? 但是,如果语言使用某些东西来表示它不仅仅是文本或数字(例如$ in $ address),它实际上应该没有区别,因为这会告诉编译器后面的内容将被视为变量(在这种情况下)。 无论如何,它归结为语言设计者想要用作他们语言的规则。
答案 19 :(得分:0)
我认为简单的答案是它可以,限制是基于语言的。在C ++和许多其他人中,它不能,因为语言不支持它。它没有内置到允许的规则中。
这个问题类似于问为什么国王不能在国际象棋中一次移动四个空格?这是因为在国际象棋中这是一种非法行动。可以在另一场比赛中确定吗这取决于正在播放的规则。
答案 20 :(得分:0)
编译器在编译期间也可以将变量视为一个值 所以该值可以一次又一次地递归调用该值
答案 21 :(得分:0)
在编译代码时,在词法分析阶段避免回溯。像Apple这样的变量; ,当它在词法分析阶段遇到字母“A”字符时,编译器会立即知道它的标识符。但是,像123apple这样的变量; ,编译器无法确定它是一个数字还是标识符,直到它命中'a',并且它需要回溯到词法分析阶段以确定它是一个变量。但是编译器不支持它。
答案 22 :(得分:0)
编译器具有7个阶段,如下所示:
在词汇分析阶段,在编译代码时避免了回溯。像Apple这样的变量,在词法分析阶段,编译器在遇到字母“ A”字符时会立即知道其标识符。但是,对于像123apple这样的变量,编译器在命中“ a”之前将无法确定其数字还是标识符,并且需要回溯到词法分析阶段才能确定它是变量。但是编译器不支持。
在解析令牌时,只需查看第一个字符即可确定它是标识符还是文字,然后将其发送给正确的函数进行处理。这就是性能优化。
答案 23 :(得分:0)
声明变量可能没有什么问题,但是当它尝试在其他地方使用该变量时存在一些歧义:
让1 =“世界你好!” 打印(1) 打印(1)
print是接受所有类型变量的通用方法。因此在这种情况下,编译器不知道程序员(1)指的是:整数值1还是存储字符串值的1。 在这种情况下,对于编译器而言,允许定义类似的内容可能会更好,但是当尝试使用这些含糊不清的内容时,请带一个带有纠正功能的错误以解决该错误并清除歧义。