变量声明和变量定义


  • 变量定义:用于为变量分配存储空间,还可为变量指定初始值。程序中,变量有且仅有一个定义。

  • 变量声明:用于向程序表明变量的类型和名字。

  • 定义也是声明,extern声明不是定义

  • 定义也是声明:当定义变量时我们声明了它的类型和名字。
  • extern声明不是定义:通过使用extern关键字声明变量名而不定义它。
    [注意]
    变量在使用前就要被定义或者声明。
    在一个程序中,变量只能定义一次,却可以声明多次。
    定义分配存储空间,而声明不会。
   C++程序通常由许多文件组成,为了让多个文件访问相同的变量,C++区分了声明和定义。变量的定义(definition)用于为变量分配存储空间,还可以为变量指定初始值。在程序中,变量有且仅有一个定义。声明(declaration)用于向程序表明变量的类型和名字。定义也是声明:当定义变量的时候我们声明了它的类型和名字。可以通过使用extern声明变量名而不定义它。不定义变量的声明包括对象名、对象类型和对象类型前的关键字extern。extern声明不是定义,也不分配存储空间。事实上它只是说明变量定义在程序的其他地方。程序中变量可以声明多次,但只能定义一次。只有当声明也是定义时,声明才可以有初始化式,因为只有定义才分配存储空间。初始化式必须要有存储空间来进行初始化。如果声明有初始化式,那么它可被当作是定义,即使声明标记为extern。任何在多文件中使用的变量都需要有与定义分离的声明。在这种情况下,一个文件含有变量的定义,使用该变量的其他文件则包含该变量的声明(而不是定义)。

如何清晰的区分变量声明和定义


extern通知编译器变量在其他地方被定义


1.extern告诉编译器变量在其他地方定义了。

例如:

extern int i;       //声明,不是定义
int i;              //声明,也是定义,未初始化

带有初始化式的声明必定式定义


2.如果声明有初始化式,就被当作定义,即使前面加了extern。
只有当extern声明位于函数外部时,才可以被初始化。

例如:

extern double pi=3.141592654;  //定义

函数的声明和定义


3.函数的声明和定义区别比较简单,带有{ }的就是定义,否则就是声明。

例如:

extern double max(double d1,double d2);  //声明

除非有extern关键字,否则都是变量的定义。


4.除非有extern关键字,否则都是变量的定义。

例如:

extern int i; //声明
int i; //定义          

程序模块化设计风格


概要


1. 不要把变量定义放入.h文件,这样容易导致重复定义错误。永远不要在.h文件中定义变量。定义变量和声明变量的区别在于定义会产生内存分配的操作,是汇编阶段的概念;而声明则只是告诉包含该声明的模块在连接阶段从其它模块寻找外部函数和变量2. 尽量使用static关键字把变量定义限制于该源文件作用域,除非变量被设计成全局的。3. 可以在头文件中声明一个变量,在用的时候包含这个头文件就声明了这个变量。

模块化要点


 (1) 模块即是一个.c文件和一个.h文件的结合,头文件(.h)中是对于该模块接口的声明;(2) 某模块提供给其它模块调用的外部函数及数据需在.h中文件中冠以extern关键字声明;(3) 模块内的函数和全局变量需在.c文件开头冠以static关键字声明;(4) 永远不要在.h文件中定义变量!定义变量和声明变量的区别在于定义会产生内存分配的操作,是汇编阶段的概念;而声明则只是告诉包含该声明的模块在连接阶段从其它模块寻找外部函数和变量。

一般情况下头文件中只放变量的声明,因为头文件要被其他文件包含(即#include),如果把定义放到头文件的话,就不能避免多次定义变量,C++不允许多次定义变量,一个程序中对指定变量的定义只有一次,声明可以无数次。

不过有三个例外,一下三中实体的定义也可放到头文件中。

1.值在编译时就已知的const 变量的定义可以放到头文件中
如:const int num(10);
2.类的定义可以放到头文件中
3.inline 函数

这三个实体可以定义在多个源文件中,只要在每个源文件中的定义相同。

示例程序


#include <stdio.h>
#include <stdlib.h>//  是定义,定义了A为整型的外部变量
//  C中定义的变量默认就是extern的,
//  因此一般来说int a = 10 <==> extern int a = 10;
/*extern */int a = 10;
//如果声明有初始化式,就被当作定义,即使前面加了extern。
//只有当extern声明位于函数外部时,才可以被初始化。int main(void)
{extern int  a;           //  声明一个外部extern的int型变量a//  这是个声明而不是定义,声明A是一个已经定义了的外部变量//  注意:声明外部变量时可以把变量类型去掉如:extern a;printf("a = %d\n", a);return EXIT_SUCCESS;
}

在这个程序中,我们再函数外部定义了一个变量
注extern int a = 10;只有当extern声明位于函数外部时,才可以被初始化。
我们后面还会提到这个问题

#include <stdio.h>
#include <stdlib.h>int main(void)
{int a;                  //  定义一个变量, 不初始化int b = 10;             //  定义一个变量, 同时进行初始化extern int  c;          //  声明一个外部extern的int型变量aprintf("a = %d\n", a);printf("b = %d\n", b);printf("c = %d\n", c);extern int d = 10;return EXIT_SUCCESS;
}

在这个程序中,

int a;是个定义,但是未初始化,打印他的值式不确定的,因此编译时会报未初始化的异常。

int b = 10; 是个定义,并且被正确初始化,打印b的值没有问题。

但是是个声明,如果要对c进行读写操作,而我们并没有对c进行定义,因此语法检查没有问题,但是在链接时,连接器会找不到c的地址。

对于d再明显不过了,前面我们提到过如果声明有初始化式,就被当作定义,即使前面加了extern。但是只有当extern声明位于函数外部时,才可以被初始化。

现在这个定义很明显被gcc编译器认为是错误的。

C语言中声明和定义详解相关推荐

  1. java的匿名函数_JAVA语言中的匿名函数详解

    本文主要向大家介绍了JAVA语言中的匿名函数详解,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助. 一.使用匿名内部类 匿名内部类由于没有名字,所以它的创建方式有点儿奇怪.创建格式如下: ...

  2. C语言 中的 数据类型 超详解

    C语言 中的 数据类型 超详解 一.整型(int.short.long.long long) 1.有符号整型 有符号整型的数据类型通常包括 int.short.long.long long 四种,因为 ...

  3. C++中的宏定义详解

    转载自:C++中的宏定义 和 C++宏定义详解 目录 一.#define解析 1 #define命令剖析 1.1   #define的概念 1.2 宏替换发生的时机 1.3 ANSI标准说明了五个预定 ...

  4. c 语言 声明 定义,C/C++语言声明与定义详解

    C/C++语言中,声明(Declaration)与定义(Definition)很容易混淆,但是正确使用声明与定义对编译器很重要.本文详细说明了声明与定义的区别. 名词解释 声明(Declaration ...

  5. c语言中声明外部函数需要添加的关键字,C语言中声明和定义的区别——分析extern关键词。...

    一直很迷惑C语言中的声明和定义的有些实践中的用法,说迷惑实践是因为声明和定义的概念上的区别是很明确的. 定义和声明的区别(主要针对变量): 定义是要为变量分配存储空间,还可以在定义的时候为变量指定初始 ...

  6. C语言怎么判断字符YN,c语言中的宏_详解(转)

    1. 简单宏定义 简单的宏定义有如下格式: [#define指令(简单的宏)] #define 标识符替换列表 替换列表是一系列的C语言记号,包括标识符.关键字.数.字符常量.字符串字面量.运算符和标 ...

  7. C语言中数组的使用详解

    文章来源: 学习通http://www.bdgxy.com/ 目录 1 数组的基本概念 2 数组定义语法 3 一维数组的初始化 3.1 全部初始化 3.2 部分元素赋初值 3.3 省略长度赋初值 4 ...

  8. c语言中截取字符串 sub,详解C++ string常用截取字符串方法

    string常用截取字符串方法有很多,但是配合使用以下两种,基本都能满足要求: find(string strSub, npos); find_last_of(string strSub, npos) ...

  9. (char*)x C语言中的和*的详解

    C语言中的指针是个让人看着,想着就头疼的问题;学习指针之前要先要懂得几个概念,在此先根据自己实际工作中遇到的几个例子说明一下.配上程序和编译结果. &和*在C语言中的含义:&取地址,* ...

最新文章

  1. 【Android Gradle】安卓应用构建流程 ( 资源文件编译 )
  2. kubernetes1.8.4 安装指南 -- 9. calico
  3. 如何查找历史版本的SAP UI5 API文档
  4. Android之elevation实现阴影效果
  5. spring rmi_Spring远程支持和开发RMI服务
  6. 创新小组 实战Git团队企操作手册_精华版本
  7. WPF TreeViewItem
  8. HDU 1596 find the safest road
  9. Oracle数据库REDO损坏ora-00333修复手札
  10. 《计算机安全与防护》教学反思,“计算机安全与防护教学设计”教学设计...
  11. hdu3709——数位dp+枚举
  12. DataSet-如何优雅使用DataSet,看完此篇文章完全理解C7N/choerodon/猪齿鱼 UI中的DataSet
  13. HDU 2510 符号三角形
  14. java attachment_Java 接收邮件(接收多附件)
  15. 支付宝集福攻略,作为程序员的你集福了么?
  16. Ubuntu 20.04添加临时/永久路由
  17. ZUCC_操作系统原理实验_Lab9进程的通信消息队列
  18. 低代码、端到端,一小时构建IoT示例场景,声网发布灵隼物联网云平台
  19. 【汇智学堂】-python小游戏(生成.exe文件)
  20. 10万以内数字转换为中文小写

热门文章

  1. 2021年了你还不了解新式类与经典类?
  2. 休谟的“归纳问题”——关于归纳方法的批判
  3. Java三个月速成学习路线图
  4. 玄幻:开局选择瑶池,我只想默默签到!(二)
  5. 2019-6-27-WPF-如何给定两个点画出一条波浪线
  6. shopee入驻条件费用-shopee 2020年最新的入驻须知
  7. Looking for the Devil in the Details:Learning Trilinear Attention Sampling Network for FGVC-笔记
  8. python集合的基本运算
  9. 闲看庭前花开花落,漫随天边云卷云舒
  10. Java反射系列--Type接口及其子接口