zoukankan      html  css  js  c++  java
  • C++:函数先声明后实现

      贼神奇的是,直到昨天在写flex规则的时候我才知道C++中的函数要么在使用之前先定义,要么将实现放在调用之前,不允许先调用后实现。之前一年多竟然不知道这件事,汗````,当然也是可能这件事本身和我思考方向是反着的,所以之前从来没有出现类似的问题。

      具体来说就是,这段代码会报错:

    #include<iostream>
    using namespace std;
    
    int main(){
        halfpoint();
        return 0;
    }
    void halfpoint(){
        cout<<"hello"<<endl;
    }

      而这段则不会

    #include<iostream>
    using namespace std;
    void halfpoint(){
        cout<<"hello"<<endl;
    }
    int main(){
        halfpoint();
        return 0;
    }

      解决的方法还有先声明:

    #include<iostream>
    using namespace std;
    void halfpoint();
    int main(){
        halfpoint();
        return 0;
    }
    void halfpoint(){
        cout<<"hello"<<endl;
    }

    这个问题在flex规则的编写时也有体现,比如下面的代码

    {%
    void yyerror(char *s);
    %}
    <comment><<EOF>>    {yyerror("EOF in comment");
    yyterminate();}
    %%
    void yyerror(char *s){
    printf("#%d ERROR "%s"
    ",curr_lineno,&(*s));
    return;}

    当初一直好奇为什么必须先加一个对yyerror的定义,后来明白是因为在处理EOF错误时用到了这个函数,但是还没有实现。

    为什么要先声明呢?我查阅了一些他人的回答,总结了一下:

    It should be considered an error. But C is an ancient language, so it's only a warning.
    Compiling with -Werror (gcc) fixes this problem.

    When C doesn't find a declaration, it assumes this implicit declaration: int f();, which means the function can receive whatever you give it, and returns an integer. If this happens to be close enough (and in case of printf, it is), then things can work. In some cases (e.g. the function actually returns a pointer, and pointers are larger than ints), it may cause real trouble.

    Note that this was fixed in newer C standards (C99, C11). In these standards, this is an error. However, gcc doesn't implement these standards by default, so you still get the warning.
    如果不先声明的话,当调用该函数时,编译器发现一个不认识的函数调用,不知道该函数的返回类型,就假设为int类型,等后面编译的时候编译器看到实际的函数,它认为有两个同名的函数,一个是文件中的函数,一个是编译器假设返回int的那个。为了防止编译器假设函数的返回类型,你可以显式地告诉它。告诉编译器函数会返回什么类型的语句就叫函数声明。
    函数声明给出了函数名、返回值类型、参数列表(重点是参数类型)等与该函数有关的信息,称为函数原型(Function Prototype)。函数原型的作用是告诉编译器(1)函数的返回值(2)参数的类型,参数的个数,方便编译器来初步排查错误。
    其实有时候,我们没有刻意的写函数原型,只是将函数的实现放置在了调用前面,这其实是相当于实现和声明的结合。
    初学者编写的代码都比较简单,顶多几百行,完全可以放在一个源文件中。对于单个源文件的程序,通常是将函数定义放到 main() 的后面,将函数声明放到 main() 的前面,这样就使得代码结构清晰明了,主次分明。

    使用者往往只关心函数的功能和函数的调用形式,很少关心函数的实现细节,将函数定义放在最后,就是尽量屏蔽不重要的信息,凸显关键的信息。将函数声明放到 main() 的前面,在定义函数时也不用关注它们的调用顺序了,哪个函数先定义,哪个函数后定义,都无所谓了。

    然而在实际开发中,往往都是几千行、上万行、百万行的代码,将这些代码都放在一个源文件中简直是灾难,不但检索麻烦,而且打开文件也很慢,所以必须将这些代码分散到多个文件中。对于多个文件的程序,通常是将函数定义放到源文件(.c文件)中,将函数的声明放到头文件(.h文件)中,使用函数时引入对应的头文件就可以,编译器会在链接阶段找到函数体。

    前面我们在使用 printf()、puts()、scanf() 等函数时引入了 stdio.h 头文件,很多初学者认为 stdio.h 中包含了函数定义(也就是函数体),只要有了头文件就能运行,其实不然,头文件中包含的都是函数声明,而不是函数定义,函数定义都放在了其它的源文件中,这些源文件已经提前编译好了,并以动态链接库或者静态链接库的形式存在,只有头文件没有系统库的话,在链接阶段就会报错,程序根本不能运行。

    除了函数,变量也有定义和声明之分。实际开发过程中,变量定义需要放在源文件(.c文件)中,变量声明需要放在头文件(.h文件)中,在链接程序时会将它们对应起来
     
  • 相关阅读:
    项目总结
    -webkit-background-clip渲染问题
    《编写可维护的JavaScript》- 类型检测
    百度ECharts使用
    使用HBuilderX将vue项目打包成app
    浅谈 asp.net core web api
    ASP.NET Core
    ASP.NET Core
    [翻译] 探究 Asp.net core 中间件 JWT bearer authentication 背后的技术
    ASP.NET Core
  • 原文地址:https://www.cnblogs.com/jiading/p/10799791.html
Copyright © 2011-2022 走看看