代码之家  ›  专栏  ›  技术社区  ›  Jeremiah

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

  •  121
  • Jeremiah  · 技术社区  · 17 年前

    我在和一个新的C++开发人员合作时,他问了一个问题:“为什么变量名不能从数字开始?”

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

    这是正确的答案吗?还有什么理由吗?

    string 2BeOrNot2Be = "that is the question"; // Why won't this compile?
    
    24 回复  |  直到 7 年前
        1
  •  97
  •   skiphoppy    17 年前

    因为这样一个数字串将是一个有效的标识符和一个有效的数字。

    int 17 = 497;
    int 42 = 6 * 9;
    String 1111 = "Totally text";
    
        2
  •  108
  •   Pyrolistical    17 年前

    好好想想这个:

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

    A是什么?2?还是42?

    提示,如果您没有得到它,数字后面的d表示数字前面的数字是双字面值。

        3
  •  42
  •   geeksal    9 年前

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

    在过去,fortran或basic等语言的解析器不需要使用空格。所以,基本上,以下是相同的:

    10 V1=100
    20 PRINT V1
    

    10V1=100
    20PRINTV1
    

    现在假设允许使用数字前缀。你怎么解释这个?

    101V=100
    

    作为

    10 1V = 100
    

    或作为

    101 V = 100
    

    或作为

    1 01V = 100
    

    所以,这是违法的。

        4
  •  34
  •   Jiayang    11 年前

    因为编译时在词汇分析中避免了回溯。变量如下:

    Apple;
    

    当编译器遇到字母“A”时,它马上就会知道它是一个标识符。

    但是变量如下:

    123apple;
    

    编译器将无法决定它是一个数字还是标识符,直到它到达“a”,结果它需要回溯。

        5
  •  13
  •   Ken Gentle    17 年前

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

    空间不重要的语言(如algol和原始的fortran,如果我记得正确的话)不能接受数字来开始标识符。

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

        6
  •  7
  •   allyourcode    16 年前

    我同意允许标识符以数字开头是很方便的。有一两个人提到,您可以通过在标识符前面加下划线来绕过这个限制,但这确实很难看。

    我认为问题的一部分来自数字字面值,例如0xDeadBeef,这使得很难为可以以数字开头的标识符制定易于记忆的规则。一种方法是允许任何匹配的[a-z a-z_uux]+不是关键字或数字文本。问题是,这会导致一些奇怪的事情,比如允许吃0块死肉,但不允许吃0块死肉。最后,我认为我们应该公平对待所有的肉类。

    当我第一次学习C时,我记得我觉得变量名的规则是武断和限制性的。最糟糕的是,他们很难记住,所以我放弃了学习他们的努力。我只是做了自己认为正确的事情,而且效果很好。现在我已经学了很多了,它看起来并不那么糟糕,我终于有机会好好学习了。

        7
  •  6
  •   William    17 年前

    这可能是由于一些原因而做出的决定,当您解析令牌时,您只需查看第一个字符来确定它是标识符还是文本,然后将其发送到正确的函数进行处理。所以这是一个性能优化。

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

    还有一些文体含义,标识符应该是助记法,所以单词比数字更容易记住。在接下来的几十年里,当许多原始语言被写下来设置风格时,他们没有考虑用“2”替换“to”。

        8
  •  4
  •   mkClark    17 年前

    使用数字开始变量名会使编译或插入期间的错误检查更加复杂。

    允许使用以数字开头的变量名可能会给语言设计者带来巨大的问题。在源代码分析过程中,每当编译器/解释器遇到一个以数字开头的标记,而该标记需要一个变量名,它就必须搜索一组庞大而复杂的规则,以确定该标记到底是一个变量还是一个错误。添加到语言解析器的复杂性可能无法证明此功能的合理性。

    据我所知(大约40年),我认为我从未使用过允许使用数字开始变量名的语言。我确信这至少做过一次。也许这里有人在某个地方看到过这个。

        9
  •  4
  •   staticsan    17 年前

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

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

    但是,如果您的语言有一个唯一的可识别字符来表示变量名,则可以将其设置为以数字开头。类似的规则变体也可用于允许变量名中有空格。但最终的语言可能与任何流行的传统语言都不太相似。

    举一个非常简单的HTML模板语言的例子,它允许变量以数字开头并有嵌入的空格,请看 Qompose .

        10
  •  4
  •   Nicholas Carey    15 年前

    因为如果允许关键字和标识符以数字字符开头,那么lexer(编译器的一部分)就无法在不变得更复杂(更慢)的情况下轻松区分数字文本和关键字的开头。

        11
  •  4
  •   Kyle Jones    14 年前

    限制是任意的。各种LISP允许符号名称以数字开头。

        12
  •  4
  •   sbagdat    13 年前

    变量名不能以数字开头,因为它可能导致以下问题:

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

    C值多少?是4,或者是10!

    另一个例子:

    float 5 = 25;
    float b = 5.5;
    

    是前5个数字,还是一个对象(。运算符) 第二个5也有类似的问题。

    可能还有其他原因。所以,我们不应该在变量名的开头使用任何数字。

        13
  •  4
  •   brad    11 年前

    COBOL允许变量以数字开头。

        14
  •  2
  •   Kevin    17 年前

    C++不能拥有它,因为语言设计者把它当作规则。如果你要创建你自己的语言,你当然可以允许它,但是你可能会遇到和他们一样的问题,并且决定不允许它。可能导致问题的变量名示例:

    0x,2D,5555

        15
  •  2
  •   caving    16 年前

    放松句法惯例的一个关键问题是在编码过程中引入认知失调。你如何看待你的代码可能会受到缺乏清晰性的影响。

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

        16
  •  1
  •   David Thornley    17 年前

    可能是因为它使人们更容易分辨它是数字还是标识符,而且是因为传统。拥有可以以数字开头的标识符不会使词汇扫描复杂化。

    并非所有语言都有以数字开头的禁止标识符。在forth中,它们可以是数字,小整数通常被定义为forth字(本质上是标识符),因为将2作为一个例程推送到堆栈中比将“2”识别为值为2的数字更快。(在处理来自编程器或磁盘块的输入时,第四个系统将按空格分割输入。它将尝试在字典中查找标记,以查看它是否是已定义的单词,如果不是,则尝试将其转换为数字,如果不是,则标记错误。)

        17
  •  1
  •   Jason Baker    16 年前

    假设您允许符号名以数字开头。现在假设您想要命名一个变量12345foobar。您如何将其与12345区分开来?实际上,使用正则表达式并不难。问题实际上是性能问题。我不能真正解释为什么这是非常详细的,但它本质上归结为一个事实,即区分12345foobar和12345需要回溯。这使得正则表达式不具有确定性。

    对此有更好的解释 here .

        18
  •  1
  •   Vivek    12 年前

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

        19
  •  0
  •   kemiller2002    17 年前

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

    这个问题类似于在下棋时国王为什么不能一次移动四个空格?因为下棋是非法的。在另一场比赛中可以吗?这取决于游戏规则。

        20
  •  0
  •   cjtech    14 年前

    最初,它只是因为更容易记住(您可以赋予它更多的意义)变量名作为字符串而不是数字,尽管数字可以包含在字符串中以增强字符串的含义,或者允许使用相同的变量名,但将其指定为具有单独但相近的含义或上下文。例如,loop1、loop2等总是让您知道您在一个循环中,并且/或者loop2是loop1中的一个循环。 您更喜欢哪个变量(更有意义):地址或1121298?哪个更容易记住? 但是,如果语言使用某种东西来表示它不仅仅是文本或数字(例如$in$address中的$in),那么它确实不应该有什么区别,因为这会告诉编译器接下来的内容将被视为变量(在本例中)。 在任何情况下,归根结底就是语言设计者想要用什么作为他们语言的规则。

        21
  •  0
  •   aravinth    10 年前

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

        22
  •  0
  •   Angelin Nadar    8 年前

    在词法分析阶段,在编译代码时避免了回溯。 . 像apple;这样的变量,当编译器在词法分析阶段遇到字母__a_字符时,它马上就会知道它的标识符。但是,像123Apple;这样的变量,编译器将无法决定它的数字或标识符,直到它到达__a_,它需要回溯到词法分析阶段来确定它是一个变量。但编译器不支持它。

    Reference

        23
  •  0
  •   Harikesh    7 年前

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

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

    在编译代码时,在词汇分析阶段避免了回溯。像Apple这样的变量,当编译器在词法分析阶段遇到字母__a_字符时,它马上就会知道它的标识符。但是,像123Apple这样的变量,编译器将无法决定它的数字或标识符,直到它到达__a_,它需要回溯到词法分析阶段来确定它是一个变量。但编译器不支持它。

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

        24
  •  0
  •   Ali Torabi    7 年前

    当涉及到声明变量时,它可能没有什么问题。但是当它尝试在其他地方使用该变量时,会有一些含糊不清的地方,比如:

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

    print是接受所有类型变量的通用方法。所以在这种情况下,编译器不知道程序员指的是哪个(1):整数值的1或存储字符串值的1。 在这种情况下,编译器最好允许定义类似的东西,但是当尝试使用这种模棱两可的东西时,请使用具有修正功能的错误来修复错误并清除这种模棱两可。

    推荐文章