为什么在C语言中变量名可以以$开头?
Why can you start a variable name with $ in C?
我的印象是变量名只能以字母和 _ 开头,但是在测试时,我还发现变量名可以以 $ 开头,如下所示:
代码
#include <stdio.h>
int main() {
int myvar=13;
int $var=42;
printf("%d\n", myvar);
printf("%d\n", $var);
}
输出
13
42
根据this resource,它说你不能在 C 中以 $ 开头变量名,这是错误的(至少在使用我的 gcc 版本编译时,Apple LLVM 版本 10.0.1(clang- 1001.0.46.4))。我在网上找到的其他资源似乎也表明变量不能以 $ 开头,这就是我感到困惑的原因。
这些文章是否只是没有提到这种细微差别,如果是,为什么这是 C 的一个特性?
This 回答了您的问题:
In GNU C, you may normally use dollar signs in identifier names. This is because many traditional C implementations allow such identifiers. However, dollar signs in identifiers are not supported on a few target machines, typically because the target assembler does not allow them.
在 C 2018 标准中,第 6.4.2 条第 1 段允许实现允许标识符中的其他字符。
它将 identifier 定义为 identifier-nondigit 字符后跟任意数量的 identifier-nondigit 或 数字 个字符。它将 digit 定义为“0”到“9”,并将 identifier-nondigit 字符定义为:
- a nondigit,是下划线,“a”到“z”,或“A”到“Z”之一,
- a 通用字符名称,或
- 其他实现定义的字符。
因此,实现可以定义标识符中允许的其他字符。
作为通用字符名包含的字符是那些列在C标准附件D范围内的字符。
resource you link to 有几个地方是错误的:
Variable names in C are made up of letters (upper and lower case) and digits.
这是错误的;标识符可以在每个符合标准的实现中包含下划线和上述通用字符,在允许它们的实现中包含其他字符。
$ not allowed -- only letters, and _
这是不正确的。 C 标准不要求实现允许“$”,但它不禁止实现允许它。某些实现允许使用“$”,而其他实现则不允许。可以说不属于strictly conforming C programs,但有可能属于conforming C programs.
TL;DR: 是汇编器而不是编译器
好的,所以我对此进行了一些研究。它不是真正允许的,但是将它排除在外的是什么作为程序集通过。尝试执行以下操作失败:
#include <stdio.h>
extern int $func();
int main() {
int myvar=13;
int $var=42;
printf("%d\n", myvar);
printf("%d\n", $var);
$func();
}
joshua@nova:/tmp$ gcc -c test.c
/tmp/ccg7zLVB.s: Assembler messages:
/tmp/ccg7zLVB.s:31: Error: operand type mismatch for `call'
joshua@nova:/tmp$
我从架子上取下了 K&R C 版本 2(包括 ANSI C),上面写着 "Identifiers are a sequence of letters and digits. The first character must be a letter; the underscore _
character counts as a letter. Upper and lower case letters are different. Identifiers may have any length ... [obsolete verbiage omitted]."
此参考文献明显过时;几乎每个人都接受 high-unicode 作为字母。发生的事情是后端汇编程序按字节查看符号,每个设置高位的字节都算作一个字母。如果你疯狂到在字符串字面量之外使用 shift-jis,混乱就会接踵而至;但除此之外,这往往效果很好。
我访问了 draft of C18,上面写着 identifier-nondigit: nondigit ; nondigit ; universal-character-name other-implementation-defined-characters
。因此,允许实现允许额外的字符。
对于universal-character-name
,我们有一个限制:“通用字符名称不得指定短标识符小于00A0的字符
除了 0024 ($)、0040 (@) 或 0060 ('),也不在 D800 到 DFFF 范围内(含)。"
以下代码仍然按预期在汇编过程中阻塞:
#include <stdio.h>
extern int \U00000024func();
int main()
{
return \U00000024func();
}
构建以下代码:
#include <stdio.h>
extern int func\U00000024();
int main()
{
return func\U00000024();
}
这在 GCC 和 LLVM 中是允许的,因为许多传统的 C 实现都允许这样的标识符。
其中一个原因是 VMS 通常使用这些,其中许多系统库例程的名称类似于 SYS$SOMETHING
。
这里是 GCC 文档的 link 描述:
取决于 C 的方言和选择的选项。历史上,当 C 是新的时,一些 C 支持 $ 以与现有库兼容。您可能需要使用命令行选项来启用 $ 或另一个选项来转换是否严格符合 C 对您有价值。
一段历史:在我早年的时候,我进入了足够多的大型机房间,知道 $ 是 IBM 大型机称为 "national characters" 的 $、# 和 @ 之一,它可以出现在标识符中PL/1 和大型机汇编程序等编程语言。这适用于一些大型机的衍生产品,例如 IBM 1130。在我看来,早期的冲击式打印机使用异形块和 CRT 终端进行打印,可以换出这些字符以满足外国客户的国家需求. IBM 1403 打印机有许多 "print chains" 可供选择,用于不同的人类语言和技术目的。
一些非 IBM 标识符至少出现在其中的一些字符上。 GNU C、VMS 和 JavaScript 保留了“$”。在大多数语言中,“$”是唯一一个似乎幸存至今的旧字符,甚至作为一个选项。奇怪的是,在早期的 IBM 时代,下划线对于标识符名称是无效的。
我的印象是变量名只能以字母和 _ 开头,但是在测试时,我还发现变量名可以以 $ 开头,如下所示:
代码
#include <stdio.h>
int main() {
int myvar=13;
int $var=42;
printf("%d\n", myvar);
printf("%d\n", $var);
}
输出
13
42
根据this resource,它说你不能在 C 中以 $ 开头变量名,这是错误的(至少在使用我的 gcc 版本编译时,Apple LLVM 版本 10.0.1(clang- 1001.0.46.4))。我在网上找到的其他资源似乎也表明变量不能以 $ 开头,这就是我感到困惑的原因。
这些文章是否只是没有提到这种细微差别,如果是,为什么这是 C 的一个特性?
This 回答了您的问题:
In GNU C, you may normally use dollar signs in identifier names. This is because many traditional C implementations allow such identifiers. However, dollar signs in identifiers are not supported on a few target machines, typically because the target assembler does not allow them.
在 C 2018 标准中,第 6.4.2 条第 1 段允许实现允许标识符中的其他字符。
它将 identifier 定义为 identifier-nondigit 字符后跟任意数量的 identifier-nondigit 或 数字 个字符。它将 digit 定义为“0”到“9”,并将 identifier-nondigit 字符定义为:
- a nondigit,是下划线,“a”到“z”,或“A”到“Z”之一,
- a 通用字符名称,或
- 其他实现定义的字符。
因此,实现可以定义标识符中允许的其他字符。
作为通用字符名包含的字符是那些列在C标准附件D范围内的字符。
resource you link to 有几个地方是错误的:
Variable names in C are made up of letters (upper and lower case) and digits.
这是错误的;标识符可以在每个符合标准的实现中包含下划线和上述通用字符,在允许它们的实现中包含其他字符。
$ not allowed -- only letters, and _
这是不正确的。 C 标准不要求实现允许“$”,但它不禁止实现允许它。某些实现允许使用“$”,而其他实现则不允许。可以说不属于strictly conforming C programs,但有可能属于conforming C programs.
TL;DR: 是汇编器而不是编译器
好的,所以我对此进行了一些研究。它不是真正允许的,但是将它排除在外的是什么作为程序集通过。尝试执行以下操作失败:
#include <stdio.h>
extern int $func();
int main() {
int myvar=13;
int $var=42;
printf("%d\n", myvar);
printf("%d\n", $var);
$func();
}
joshua@nova:/tmp$ gcc -c test.c
/tmp/ccg7zLVB.s: Assembler messages:
/tmp/ccg7zLVB.s:31: Error: operand type mismatch for `call'
joshua@nova:/tmp$
我从架子上取下了 K&R C 版本 2(包括 ANSI C),上面写着 "Identifiers are a sequence of letters and digits. The first character must be a letter; the underscore _
character counts as a letter. Upper and lower case letters are different. Identifiers may have any length ... [obsolete verbiage omitted]."
此参考文献明显过时;几乎每个人都接受 high-unicode 作为字母。发生的事情是后端汇编程序按字节查看符号,每个设置高位的字节都算作一个字母。如果你疯狂到在字符串字面量之外使用 shift-jis,混乱就会接踵而至;但除此之外,这往往效果很好。
我访问了 draft of C18,上面写着 identifier-nondigit: nondigit ; nondigit ; universal-character-name other-implementation-defined-characters
。因此,允许实现允许额外的字符。
对于universal-character-name
,我们有一个限制:“通用字符名称不得指定短标识符小于00A0的字符
除了 0024 ($)、0040 (@) 或 0060 ('),也不在 D800 到 DFFF 范围内(含)。"
以下代码仍然按预期在汇编过程中阻塞:
#include <stdio.h>
extern int \U00000024func();
int main()
{
return \U00000024func();
}
构建以下代码:
#include <stdio.h>
extern int func\U00000024();
int main()
{
return func\U00000024();
}
这在 GCC 和 LLVM 中是允许的,因为许多传统的 C 实现都允许这样的标识符。
其中一个原因是 VMS 通常使用这些,其中许多系统库例程的名称类似于 SYS$SOMETHING
。
这里是 GCC 文档的 link 描述:
取决于 C 的方言和选择的选项。历史上,当 C 是新的时,一些 C 支持 $ 以与现有库兼容。您可能需要使用命令行选项来启用 $ 或另一个选项来转换是否严格符合 C 对您有价值。
一段历史:在我早年的时候,我进入了足够多的大型机房间,知道 $ 是 IBM 大型机称为 "national characters" 的 $、# 和 @ 之一,它可以出现在标识符中PL/1 和大型机汇编程序等编程语言。这适用于一些大型机的衍生产品,例如 IBM 1130。在我看来,早期的冲击式打印机使用异形块和 CRT 终端进行打印,可以换出这些字符以满足外国客户的国家需求. IBM 1403 打印机有许多 "print chains" 可供选择,用于不同的人类语言和技术目的。
一些非 IBM 标识符至少出现在其中的一些字符上。 GNU C、VMS 和 JavaScript 保留了“$”。在大多数语言中,“$”是唯一一个似乎幸存至今的旧字符,甚至作为一个选项。奇怪的是,在早期的 IBM 时代,下划线对于标识符名称是无效的。