为什么/却ç允许隐函数和无类型的变量声明?(Why does/did C allow implici

2019-06-26 19:44发布

为什么是明智的语言,让功能和无类型变量隐含的声明? 我得到C是老了,但允许省略声明和默认为int()int中的变量情况下)似乎不那么理智的我,甚至当时的情况。

那么,为什么它最初推出? 是不是曾经真的有用吗? 它实际上是(仍然)使用?

注:我知道,现代的编译器给你的警告(取决于你的标志通过他们),你可以取消此功能。 这不是问题!


例:

int main() {
  static bar = 7; // defaults to "int bar"
  return foo(bar); // defaults to a "int foo()"
}

int foo(int i) {
  return i;
}

Answer 1:

见丹尼斯里奇的“C语言的发展”: http://cm.bell-labs.com/who/dmr/chist.html

例如,

与此相反的创建B的过程中发生的普遍的语法变型中,BCPL-其类型结构和表达评价的核心语义内容规则保持完整。 这两种语言是无类型,或者更确切地说,具有单个数据类型,“字”,或者“小区”,一个固定长度的比特模式。 存储器在这些语言包括这种细胞的线性阵列,并且一个单元格的内容的含义取决于所施加的操作。 +操作,例如,只是增加了使用它的操作数机器的整数加法指令,以及其它算术运算同样无意识的操作数的实际意义。 因为存储器是线性阵列,可以在细胞中作为此数组中的一个索引来解释的值,并BCPL为此目的提供的算子。 在原来的语言也被拼写RV,后来!,而B使用一元*。 因此,如果p是包含的索引的小区(或地址,或指向)的另一小区,* P指的是指向的单元格的内容,无论是作为在表达式的值或作为赋值的目标。

这typelessness用C一直持续到作者开始将它移植到不同的字长的机器:

在此期间,语言的变化,特别是在1977年,在很大程度上集中在移植和类型安全的考虑,为了应对我们预见并在相当多的代码移动到新的Interdata平台观察到的问题。 下在那个时候还是体现了其无类型的起源强有力的迹象。 指针,例如,被勉强从早期语言手册或现存代码积分存储器索引区分; 字符指针和无符号整数的算术性质的相似性使得它难以抗拒的诱惑,以确定它们。 加入无符号的类型,使无符号运算可用而不与指针操作混淆了。 同样,早期语言纵容整数和指针之间的分配,但这种做法开始被取缔; 对于类型转换的符号(称为从陵68的例子`石膏)的发明是为了更明确地指定类型转换。 通过PL / I的示例诱骗,早期Ç没有扎结构指针牢牢它们指向的结构,并且允许程序员编写指针 - >构件几乎不用考虑指针的类型; 这样的表达不加鉴别地取为于由指针指定的存储区域中的参考,而构件名称指定唯一的偏移和类型。

编程语言演变为编程习惯的改变。 在现代C和现代的编程环境中,许多程序员从来没有写过汇编语言的概念,整形和指针是可以互换的可能似乎几乎深不可测的和不合理。



Answer 2:

这是通常的故事- 歇斯底里的葡萄干 (又名“历史原因”)。

在开始的时候,是c运行在大型计算机(DEC PDP-11)64昆明植物研究所的数据和代码(后64 KIB每个)。 还有就是你能有多复杂使编译器的限制,仍然有它运行。 事实上,有怀疑,你可以在O / S采用高级语言如C,而不需要用汇编写的。 因此,有大小限制。 此外,我们正在谈论很久以前,在早期70年代中期。 计算,一般不作为成熟的一门学科,因为它是现在(和编译器的具体人多地少很好理解)。 而且,从该下导出的语言(B和BCPL)为无类型。 所有这些都是因素。

从那时起(谢天谢地)的语言已经进化。 正如在评论中得到了广泛的注意和向下投票答案,严格C99,隐含int变量和隐式函数声明都被过时。 然而,大多数编译器仍然承认旧的语法,并允许其使用,或多或少警告,向后兼容性保留,使旧的源代码将继续编译和运行,因为它总是这样。 C89主要是标准化的语言,因为它是,疣( gets() )和所有。 这是必要的,使C89的标准可以接受的。

还有,周围用旧符号旧的代码 - 我花了很多时间在一个古老的代码库(大约1982年的最古老的部分)仍然还没有完全转化为原型到处(这让我很烦激烈,但只有这么多一个人可以与多个数百万行代码)的代码库做。 很少的它仍然有“隐int变量”; 有些情况下功能都没有使用之前声明太多的地方,以及一些地方的函数的返回类型仍然是隐含int 。 如果你没有这样的食堂工作,应该感谢那些谁在你面前了。



Answer 3:

也许是最好的解释“为什么”来自这里 :

两个想法是它的类的语言中最有特点的C:和以何种方式声明语法模拟表达式语法数组和指针之间的关系,。 他们也是最经常诟病的功能之一,经常作为绊脚石初学者。 在这两种情况下,历史事件或错误加剧了他们的困难。 其中最重要的,这些一直是C语言编译器对类型错误的容忍。 如应该从上面的历史清楚,C从无类型语言的演化发展 。 这并不是突然出现最早的用户和开发者有自己的规则,一个全新的语言; 相反,我们必须不断地适应现有的方案作为开发的语言,使津贴的代码现有机构。 (后来,ANSI X3J11委员会标准化C将面临同样的问题。)

系统编程语言不一定需要类型; 你摆弄周围的字节和字,而不是花车和整数和结构和字符串。 该型系统移植到它的点点滴滴,而不是从一开始就语言的一部分。 以C已经从主要是一个系统编程语言的通用编程语言感动,它已成为在它如何处理类型更加严格。 但是,即使范式来来去去,遗留代码是永远的。 仍然有大量的代码在那里,依赖于隐含的int和标准委员会是不愿意打破任何的工作。 这就是为什么花了近30年来摆脱它。



Answer 4:

在很久很久以前,早在K&R,预ANSI天,功能看起来很不同的比他们今天所做的。

add_numbers(x, y)
{
    return x + y;
}

int ansi_add_numbers(int x, int y); // modern, ANSI C

当你调用像功能add_numbers ,没有在调用约定的一个重要区别:所有类型“提升”当函数被调用。 所以,如果你这样做:

// no prototype for add_numbers
short x = 3;
short y = 5;
short z = add_numbers(x, y);

什么情况是x被提升为inty被提升为int ,并返回类型被假定为int默认。 同样,如果你传递一个float它提升为两倍。 这些规则确保了原型是没有必要的,只要你有正确的返回类型,只要你传递的参数正确的数量和类型。

需要注意的是原型的语法是不同的:

// K&R style function
// number of parameters is UNKNOWN, but fixed
// return type is known (int is default)
add_numbers();

// ANSI style function
// number of parameters is known, types are fixed
// return type is known
int ansi_add_numbers(int x, int y);

通常的做法早在过去是为了避免大部分的头文件,而直接贴在样机代码:

void *malloc();

char *buf = malloc(1024);
if (!buf) abort();

头文件被接受为在C必要之恶,这些天,但正如现代C衍生物(Java,C#等)已经摆脱了头文件,老前辈真的不喜欢使用头文件无论是。

类型安全

据我了解关于预-C的时光,也并不总是太大的静态类型系统。 一切都是一个int ,包括指针。 在这个古老的语言,函数原型的唯一的一点是赶上元数错误。

因此,如果我们假设的功能被添加到语言,再后来增加了一个静态类型系统,这个理论解释了为什么原型是可选的。 这个理论也解释了为什么数组衰变为函数参数一起使用时的指针 - 在这个原-C,因为数组是没有什么比得到自动初始化为指向栈上的一些空间指针更多。 例如,像下面可能是可能的:

function()
{
    auto x[7];
    x += 1;
}

引文

  • c语言的发展,丹尼斯·里奇M.

在typelessness:

两种语言[B和BCPL]是无类型,或者更确切地说,具有单个数据类型,“字”或“细胞”,一个固定长度的比特模式。

在整数和指针的等价性:

因此,如果p是包含的索引的小区(或地址,或指向)的另一小区, *p指的是指向的单元格的内容,无论是作为在表达式的值或作为赋值的目标。

证据的理论原型由于尺寸的限制省略:

在开发过程中,他不断地奋斗了反对内存限制:每种语言除了充气编译器,它可以勉强配合,但每次重写取功能的优势缩小其尺寸。



Answer 5:

有些耐人寻味。 (这不是一个答案,我们其实知道答案 - 它允许向后兼容性。)

而且,人们应该看看COBOL代码库或F66库说为什么它不是在30年左右清理之前

gcc其默认不吐任何警告。

随着-Wallgcc -std=c99也吐出了正确的事

main.c:2: warning: type defaults to ‘int’ in declaration of ‘bar’
main.c:3: warning: implicit declaration of function ‘foo’

lint建成现代化功能gcc显示出它的颜色。

有趣的是现代克隆lint ,安全lint -我的意思是splint -只给出了一个默认的警告。

main.c:3:10: Unrecognized identifier: foo
  Identifier used in code has not been declared. (Use -unrecog to inhibit
  warning)

llvm C编译器clang其中也有内置到它像一个静态分析gcc ,默认情况下,吐出来的是两个警告。

main.c:2:10: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
  static bar = 7; // defaults to "int bar"
  ~~~~~~ ^
main.c:3:10: warning: implicit declaration of function 'foo' is invalid in C99
      [-Wimplicit-function-declaration]
  return foo(bar); // defaults to a "int foo()"
         ^

人们曾经认为,我们不需要为80的东西向后兼容性。 所有代码必须被清理或更换。 但事实证明,它并非如此。 大量的生产代码停留在史前非标准倍。

编辑:

我没有张贴我之前通过其他的答案看。 我可能误解了海报的意图。 但事情是有,当你用手编译你的代码,并使用切换将二进制模式在内存中的时间。 他们并不需要一个“类型系统”。 也不在PDP机在其前面的里奇和汤普森构成是这样的:

别看大胡子,看一下“切换”,这是我听到的都是用来引导机器。

而且也要看他们如何来引导UNIX本文。 这是从Unix的第7版手册。

http://wolfram.schneider.org/bsd/7thEdManVol2/setup/setup.html

事情的关键是,他们并不需要这么多的软件层管理一台机器KB大小的内存。 Knuth的MIX有4000个字。 你并不需要所有这些类型的MIX计算机程序。 您可以愉快地在这样的机器比较指针整数。

我想为什么他们这样做是相当不言自明。 所以,我把重点放在剩下多少被清理



文章来源: Why does/did C allow implicit function and typeless variable declarations?