函数的原型类似于在调用例程中声明函数吗?

时间:2019-11-02 11:18:25

标签: c function scope declaration

  

如果没有函数原型,则函数在表达式中的首次出现会隐式声明该函数。

在C语言中,如果函数返回除int以外的其他值,则习惯在调用方函数中声明函数,如第一个代码示例

但是您总是受编译器约束来编写原型,原因是他不知道该函数是谁,因为它是在main()函数下声明的。

问题是:这两个等效?在main()内编写原型还是明确声明函数会返回想要的结果吗?如果始终受限使用这两种方法之一,它将如何返回错误值?

  1. 如果函数是在与调用方函数相同的脚本中声明的(此处main()
    • 原型
    • main()中显式声明功能。
  2. 如果函数在另一个文件中声明
    • 原型
    • main()中显式声明功能

例如:

int main()
{
    double doSomething(int a);
    printf("%d", doSomething(2) );
}
double doSomething(int a)
{
     return a * 2.0;
}

vs

double doSomething(int a);

int main()
{
    printf("%d", doSomething(2) );
}
double doSomething(int a)
{
     return a * 2.0;
}

这个线程几乎是我所需要的,但是并不能回答我的所有问题。 C language - calling functions without function prototype

2 个答案:

答案 0 :(得分:4)

这两个声明是等效的,直到在第一种情况下,除main之外的其他某些函数将需要函数doSomething

在此代码段中

int main()
{
    double doSomething(int a);
    //..

有一个函数doSomething的函数原型。

根据C标准

  

函数原型是声明函数的声明,   参数的类型

在函数定义(也是其声明)之前,该函数的名称仅在main的块范围内可见。

考虑以下程序

#include <stdio.h>

void g( void )
{
    f( 20 );
}

int main(void) 
{
    void f( int );

    f( 10 );

    return 0;
}

void f( int x )
{
    printf( "x = %d\n", x );
}

编译器将为此语句发出错误

    f( 20 );

因为尚未声明名称f。

但这句话

    f( 10 );

是正确的,因为已经声明了main的块范围内的名称。

为了更清楚地说明,函数始终具有与在没有存储类说明符的块作用域中声明的变量相反的链接。

所以这个声明在main

    double doSomething(int a);

等同于声明

    extern double doSomething(int a);

即使在块范围内最初声明了函数,链接器也将找到函数定义。

答案 1 :(得分:1)

在现代C语言中,应始终在使用函数之前声明一个函数。 (这包括在使用函数之前先定义函数,因为定义是声明。)函数隐式声明返回int是C的很老版本的行为。不应使用它,编译器至少应警告一下关于它,您应该设置编译器使其成为错误,而不是警告。

函数通常在其他函数之外声明。在另一个函数中声明一个函数没有明显的错误,但是我们很少这样做,因为我们通常希望函数在整个翻译单元中可见,而不仅仅是在一个特定的位置。 (翻译单元是一个源文件,包括它通过#include指令包含的所有文件。)函数名称遵循与对象名称相同的 scope 规则:如果出现在任何文件之外功能,它具有文件范围。如果它出现在 block (括号内的语句列表,{ … },其中包括函数体)内,则它具有 block范围,并且仅在其中可见

在文件作用域或块作用域声明函数不会影响其行为。

main在这方面并不特殊。您可能会问main,因为您还很早就接受编程培训,而您大多只是从main调用函数。但是,可以从其他函数中调用函数,并且有关范围和名称可见性的规则并非main所独有。如果在文件范围内声明了函数,则其名称在翻译单元的其余部分中都是可见的。如果某个函数是在块范围内声明的,无论是在main内部还是在另一个函数中,则其名称在该块的其余部分都可见。

如果定义了一个函数来返回double,但是您在未声明的情况下使用了该函数,并且编译器允许这样做,那么您可以期望程序无法正常工作。编译器不会自动将double转换为int。函数类型对于告诉编译器函数返回的内容很重要,因为编译器期望函数返回时某些位位于特定位置,并根据该位编写指令。