为什么我们不能在声明结构变量名时使用连字符?

Why can't we use of hyphen while declaring structure variable name?

构造生日{ 整数 day:6; }b-day;

在将 b-day 声明为结构时显示以下错误:

error: expected ':', ',', ';', '}' or '__attribute__' before '-' token|

但是从变量名中删除连字符后它起作用了,为什么?

连字符用作减法和取反运算符,因此不能在变量名中使用。 (变量是用于结构还是其他类型无关紧要。)

如果你有:

int a = 1;
int b = 2;
int a-b = 3;
printf("%d\n", a-b);

那么我们会不清楚是为 a 减去 b 打印“-1”还是为变量 a-b.

打印“3”

因为 C 不允许使用连字符作为标识符名称。

基本上你只能使用字母、数字和下划线。 也不允许使用数字作为第一个字符。

引自N1570 6.4.2 标识符:

Syntax

identifier:
    identifier-nondigit
    identifier identifier-nondigit
    identifier digit

identifier-nondigit:
    nondigit
    universal-character-name
    other implementation-defined characters

nondigit: one of
    _ a b c d e f g h i j k l m
      n o p q r s t u v w x y z
      A B C D E F G H I J K L M
      N O P Q R S T U V W X Y Z

digit: one of
    0 1 2 3 4 5 6 7 8 9

这是因为标识符名称中不能使用符号'-'。当它用在一系列符号之间时,编译器会根据上下文将其视为二元或一元减号运算符。

错误信息

error: expected ':', ',', ';', '}' or 'attribute' before '-' token|

意味着编译器试图解释声明至少像

    struct birthday{
        int day:6;
    }b; -day;

你可以这样声明结构

    struct birthday{
        int day:6;
    } b_day;

即使用下划线符号而不是连字符。

无聊的答案是语言定义不允许 - 成为标识符的一部分(变量名、函数名、typedef 名、枚举常量、标记名等)。

为什么会出现这种情况可能归结为以下几点:

在预处理阶段,您的源文本被分解为一系列 标记 - 标识符、标点符号、字符串文字和数字常量。除了分隔相同类型的标记外,空格并不重要。如果你写 a=b+c;,编译器会看到标记序列 identifier (a), punctuator (=), 标识符 (b), 标点符号 (+), 标识符 (c),以及 标点符号 (;)。这是在它进行任何语法分析之前 - 它不查看该语句的含义或结构,它只是将其分解成它的组成部分。

它可以这样做是因为字符 =+ 以及 ; 可以 永远不会 成为标识符的一部分,所以它可以清楚地看到标识符开始和结束的位置1.

记号生成器是“贪婪的”,它将尽可能地构建最长的有效记号。在像

这样的声明中
int a;

你需要空格来告诉预处理器 inta 是不同的标记,否则它会尝试将它们混合成一个标记 inta。同样,在像 a=b- -c; 这样的语句中,您需要空格(或括号 a=b-(-c);)来表示您要从 b 中减去 -c,否则分词器将解释它a = b-- c,这不是你想要的。

那么,如果 - 可以成为标识符的一部分,那么 x=a-b+c 应该如何标记化? a-b 是一个还是三个?你将如何编写你的分词器以便它可以跟踪它?您是否需要 - 前后的空格来表示它是一个运算符而不是变量的一部分?

当然可以定义一种允许 - 既是运算符又是标识符的一部分的语言(参见 COBOL),但它增加了编译标记化阶段的复杂性,而且它只是简单的 更容易不允许它。


  1. 巧合的是,这就是为什么在声明指针变量时 T *p;T* p; 之间没有区别的原因 - * 永远不能成为标识符的一部分,因此不需要空格将类型与变量名分开。您可以将其写为 T*p; 甚至 T * p; ,它们将被完全相同地对待。