C语言中变量声明的歧义行为

6

i have the following code

#include<stdio.h>
int main()
{
    int a12345678901234567890123456789012345;
    int a123456789012345678901234567890123456;
    int sum;

    scanf("%d",&a12345678901234567890123456789012345);
    scanf("%d",&a123456789012345678901234567890123456);
    sum = a12345678901234567890123456789012345 + a123456789012345678901234567890123456;
    printf("%d\n",sum);

    return 0;
}

问题是,我们知道ANSI标准识别最多31个字符的变量...但是,这两个变量相同的部分达到了35个字符...但是,程序仍然可以编译并正常输出而没有任何错误和警告...
为什么呢?
难道不应该会出现重新声明的错误吗?


1
你使用的编译器是什么? - kums
Code::Blocks 13.12,GNU GCC编译器 - MD. Khairul Basar
没有人应该写出这样的代码;这些信息不应该用于正常实际编码。这个问题只与那些编写代码生成工具的人有关。 - artless noise
5个回答

15
许多编译器被构建为超出 ANSI 规范(例如,在识别长于 31 个字符的变量名称方面)以保护程序员。虽然这在您正在使用的编译器中有效,但不能保证它能在任何 C 编译器中正常工作...

10
"[...] 我们知道ANSI标准承认变量长度最多为31个字符,那么重复声明不应该会报错吗?"
其实并不一定。既然您提到了ANSI C,这是C89标准的相关部分:
“实现限制”
实现应将内部名称(宏名称或没有外部链接的标识符)的前31个字符视为重要的。相应的小写字母和大写字母是不同的。实现可以进一步限制外部名称(具有外部链接的标识符)的重要性为六个字符,并且可以忽略此类名称的字母大小写区别。这些标识符的限制都是由实现定义的。
任何在一个重要字符上不同的标识符都是不同的标识符。如果两个标识符在一个非重要字符上不同,则行为未定义。 http://port70.net/~nsz/c/c89/c89-draft.html#3.1.2 (强调是我加的)
这也被明确描述为一种常见的扩展:

标识符的长度和大小写

标识符中所有字符(具有或不具有外部链接)都是显著的,并且观察大小写区分(3.1.2)。

http://port70.net/~nsz/c/c89/c89-draft.html#A.6.5.3

因此,您只是利用编译器的C实现选择。


3

C89标准的解释详细说明了这一点:

3.1.2 标识符

尽管实现不必为了名称匹配而记住标识符的前31个字符,但程序员事实上被禁止有意创建在前31个字符中相同的两个不同标识符。因此,实现可以存储完整的标识符;它们不必截断到31个字符。

将内部名称的重要性扩展到31个字符的决定没有遭到多少反对,但保留旧的对外名称的六个字符大小写不敏感限制的决定则是最痛苦的。虽然人们强烈表达了通过要求在任何地方使用更长的名称来使C“正确”的情感,但委员会认识到,该语言在未来几年必须与其他语言和旧汇编器和链接器共存。为了不削弱对标准的支持,严格的限制已被保留。

GCC这样的编译器可以存储完整的标识符。

  • 标识符中的有效初始字符数(C90 6.1.2,C90、C99和C11 5.2.4.1,C99和C11 6.4.2)。

    对于内部名称,所有字符都是重要的。对于外部名称,重要字符的数量由链接器定义;对于几乎所有目标,所有字符都是重要的。


3
一种符合规范的实现必须支持外部标识符的至少31个字符(而您的标识符是内部的,对于C99和C11来说限制为63个字符)。事实上,所有字符都具有重要意义是标准的本意,但委员会不想通过没有提供它来使实现变得不符合规范。外部标识符的限制源于某些链接器无法提供更多支持(在C89中,只需要6个字符具有重要意义,这就是为什么旧的标准库函数名称长度不超过6个字符的原因)。准确地说,标准并没有明确规定这些限制,标准中的语言是相当宽松的:C11(n1570)5.2.4.1翻译限制。脚注18)清楚地表达了意图:尽可能避免强加固定的翻译限制。脚注19)指的是将来的语言方向6.11.3:将外部名称的重要性限制为255个字符以下(将每个通用字符名称或扩展源字符视为单个字符)是一项过时的功能,是对现有实现的让步。为了解释5.2.4.1第一句话的宽容性,请参阅C99 rationale(5.10)。

5.2.4 环境限制

C89委员会认为标准必须阐明某些能力和限制,但如何执行这些条款则是一个颇具争议的话题。

5.2.4.1 翻译限制

标准要求实现能够翻译和执行一些满足每个规定限制的程序。此标准被认为为实现者在遵守这些限制方面提供了有用的灵活性。虽然不足的实现可能会设计一个程序来满足此要求,但仍然成功地成为无用的,但C89委员会认为这种创造力可能需要比制作出实用的东西更多的工作。C89和C99委员会的意见是,实现者不应将翻译限制视为硬编码参数的值,而应将其视为衡量实现是否达标的一组标准。


2

没有限制。 实际上是有限制的,它必须足够小以适应内存,但除此之外没有限制。如果存在内置限制(我不相信有),那么这个限制非常巨大,你很难达到它。我生成了C++代码,使用两个变量,它们的最后一个字符不同,以确保名称长得不同。我得到了64KB的文件,认为这已经足够了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接