• 声明declaration与定义definition


    我们在学习c/c++的时候,最开始接触的就是变量的声明和定义。对于这两个概念大家都很熟悉,但是具体研究下来,往往比较模糊,尤其是在代码跟踪调试,对于ide提供的跳转到声明和跳转到定义,不能明确区分其差别。包括后续开发,全局变量的使用的时候,往往有各种编译问题,还有extern static等等对变量的影响。今天就根据个人经验详细说一下变量的声明和定义,以及在使用过程中容易出现的一些错误。

    字面意思

    按照最常见的解释,声明是仅仅告诉程序有这么一个数据结构类型或者函数类型;定义就是对数据结构或者函数进行设计,实现,能让程序找到最终的数据所在。
    这与分配内存很像,c中申请一块内存,并没有在真实物理内存上分配空间,只有当第一次使用的时候,才会触发一个中断,然后到物理内存上分配空间。所以申请内存就相当于声明,分配物理内存就相当于定义。

    在很多时候声明和定义是一条语句,所以非常容易混淆。

    具体例子

    //声明
    extern int a;
    
    //如果第一次出现,或者没有extern int a;,这个就是声明和定义,如果前面有extern int a;表示已经声明了,这里就是定义
    int a = 1;
    
    //声明
    struct s;
    
    //定义
    struct s{
      int num;
    }
    
    //如果是第一次出现或者没有出现过struct s;,这里就是声明定义,如果出现过struct s;,这里就是定义
    struct s{
      int num;
    }
    

    声明可以有多次声明,但定义只能有一次定义

    声明可以在多个地方对同一个内容声明,但是记住,在同一作用域内,只能声明一次

    比如在同一个函数中,不可以对同一变量声明两次

    //这样是会报错的
    extern int a;
    extern int a;
    

    但是对于同一变量在不同作用域下,可以重复声明,不同文件也属于不同作用域

    //下面这样写是没问题的
    //a.h
    extern int a;
    
    //a.c
    extern int a;
    
    //b.h
    extern int a;
    

    对于同一变量,不管在哪个作用域,都只能定义一次

    不管在哪个作用域,只要是指向同一个变量,多次定义都会报错,因为程序不知道以哪一个为准,大体报错内容如下

    multiple definition of first defined here
    error: ld returned 1 exit status
    
    //如下就会报错
    //a.h
    extern int a;
    
    //a.c
    int a = 1;
    
    //b.h
    extern int a;
    
    //b.c
    int a = 2;
    

    为什么没有用int a;举例

    上面的例子可以看到,只写了extern int a;和int a = 1;,没有用int a;举例,是因为int a的含义模糊,可能是extern int a省略了extern,表示声明;也可能是int a;定义,根据不同情况会不一样。

    之声明不定义可以吗

    不可以,如果你在很多地方写了extern int a,但是没有任何一个地方写int a;或者int a = 1;,那么你直接用a的时候,不管是赋值还是输出,都会报错,告诉你没有定义,报错日志如下

    undefined reference to
    error: ld returned 1 exit status
    
    //如下会报错
    //a.h
    extern int a;
    
    //a.c
    a = 1;
    

    extern常见的使用

    extern "C"

    因为c++为了实现类的多态等功能,每个函数编译完成后会在函数名字后面加一串字符,也就是函数名字已经被修改了,这样的话是无法写lib库的,因为lib库会根据你提供的函数名到编译好的库中查找函数位置,而c++编译出来的可执行文件中的函数名是未知的。为了避免这个问题,可以用这个把需要提供给别人,不想修改函数名的函数括起来

    全局变量

    c中的全局变量,因为少了c++类的限制,很容易在使用中出现问题。比如a.h中定义了全局变量,b.h/b.c和c.h/c.c都会使用,这时就比较麻烦,很容易出现重复定义的问题。
    比如全局变量是int a;

    都不引用a.h

    如果不引用a.h,那么在b.h/b.c中使用a时就会报错,提示为定义,那么就要在用前声明extern int a;,这样告诉编译器,可以到其他文件中查找是否定义了a。这样做法就是关系不明确,因为没有引入头文件;繁琐,因为每次使用前都要用extern int a;声明

    如果a.h中是int a;,并且引用a.h

    这样使用时相对问题少一点,但是有一个不方便的就是int a没有初始化,之所以这样没问题就是因为上面说的int a;的意义是不明确的,编译器会根据需要来确定是声明还是定义。

    如果a.h中是int a = 1;,并且引用a.h

    这是明确定义的,那么多个文件引用a.h就会报重复定义

    如果a.h中是extern int a;,并且引用a.h

    这样写是目前大家处理全局变量的常用方法,这里仅仅是声明,所以需要有一个定义,那么正好在a.c中进行定义初始化——int a = 0;
    这样在其他文件中引用a.h,都不需要额外做什么,直接用a即可,这也符合上面的逻辑,就是所有用到的地方都是extern int a;,真正定义的只有a.c中int a = 0;

  • 相关阅读:
    CentOS下安装Git
    MongoDB 从入门到精通专题教程
    mongodb分布式集群架构
    CentOS6.2 下安装中文语言包
    英语流利说 第18天
    英语流利说 第17天
    英语流利说 第16天
    英语流利说 第15天
    英语流利说 第14天
    英语流利说 第13天
  • 原文地址:https://www.cnblogs.com/studywithallofyou/p/16799991.html
Copyright © 2020-2023  润新知