什么是编程中的原型?

What are prototypes in programming?

这不是关于语言的具体问题,而是关于一般编程的问题。这个问题是在我与一位朋友就我最近从我的 C++ 课程中学到的“函数原型”展开争论之后出现的。我向他提到原型是函数 headers,您必须在代码开头创建它,以便编译器在运行时分配一些 space,然后再获取实际函数。然后我们开始讨论其他不使用函数原型的编程语言(如 java 或 python)——就我们而言——是否真的有一个类似于 C++ 的系统,只是他们自己处理,而不是让用户创建它们。

所以我们很想知道,到底什么是函数原型?他们只对 C/C++ 负责,还是其他编程语言使用它们?作为未来的程序员,我需要在这方面进行更多开发吗?感谢您的帮助!

这被大大简化了,但函数原型的原因是“一次性编译器”。

如果您的编译器只通过一次代码,它需要在调用函数实现之前知道它可以使用哪些函数。这就是原型的用武之地。

多次通过代码的编译器会构建跳转表,告诉它所有函数的位置,因此不需要函数原型。


在 C 编译器中,原型用于检查函数参数的类型和数量(即函数签名)。这个节目:

#include <stdio.h>

int main()
{
    printf("%d\n",add(3));
}

int add(int i, int j)
{
    return i+j;
}

compiles and executes in Clang 7 with a warning,即使结果没有意义(即未定义的行为)。

而这个程序包含一个函数原型:

#include <stdio.h>

int add (int, int); /* function prototype for add */

void main()
{
    printf("%d\n",add(3));
}

int add(int i, int j)
{
    return i+j;
}

fails to compile.

对于 C 和 C++,“原型”一词是指特定的声明语法。

在最早的 C 版本中,函数定义写成

int func( arg1, arg2, arg3 ) // no types in argument list, just identifiers
  int arg1;
  double arg2;
  char *arg3;
{
  // function body
}

声明写成

int func( ); // no argument list

函数参数列表仅包含标识符,没有类型信息 - 单独提供。函数声明不包含参数,仅包含 return 类型。

C++引入,C后来采用了原型语法的概念,其中类型信息包含在两个定义的参数列表中:

int func( int arg1, double arg2, char *arg3 )
{
  // function body
}

和声明

int func( int, double, char * );

这允许编译器检查函数调用中参数的数量和类型,如果它们不匹配则发出诊断,而不是等到运行时才发现是否有一个问题。

虽然仍然支持旧式函数声明和定义语法,但不应将其用于新代码开发 - 我们几乎到了“原型”一词有点多余的地步,因为原型语法是常态而不是例外。

Fortran、Pascal 和 Ada 等静态类型语言都有单独的函数 声明,但它们并不将这些声明称为原型。对于 C,“原型”指的是函数声明和定义的特定 风格 ,而不仅仅是声明本身。

C和C++编译为本地代码,支持编译单元(文件)间调用。为了从相邻的编译单元调用函数 XYZ,编译器插入一个引用“调用 XYZ”,稍后由 linker 解析。但是你需要知道在堆栈上为函数准备什么。原型无需编译整个函数即可提供该信息。

早期的 C 将所有内容都视为 int,并且由于 C 调用约定是调用者清理,作为调用者,您知道在函数 returns 之后要从堆栈中删除多少 int。如果你用三个参数调用 printf 而没有解释它是什么,C 编译器仍然可以找出要生成的代码。如果您将它拼错为 vrintf,它将编译但无法编译为 link。所以普通 C 在没有原型的情况下(或将丢失的原型视为警告)在某种程度上工作(仍然有效?)。

由于 C++ 可以将各种疯狂的东西作为函数参数传递,如果您在不先解释其参数类型的情况下尝试调用某些东西,编译器将不知道要生成什么代码,并且您会收到错误。

这篇外部文章相当不错:http://www.cplusplus.com/articles/yAqpX9L8/