C语言中声明和定义详解(待看。。
变量声明和变量定义
变量定义:用于为变量分配存储空间,还可为变量指定初始值。程序中,变量有且仅有一个定义。
变量声明:用于向程序表明变量的类型和名字。
定义也是声明,extern声明不是定义
- 定义也是声明:当定义变量时我们声明了它的类型和名字。
- extern声明不是定义:通过使用extern关键字声明变量名而不定义它。
[注意]
变量在使用前就要被定义或者声明。
在一个程序中,变量只能定义一次,却可以声明多次。
定义分配存储空间,而声明不会。
C++程序通常由许多文件组成,为了让多个文件访问相同的变量,C++区分了声明和定义。
变量的定义(definition)用于为变量分配存储空间,还可以为变量指定初始值。在程序中,变量有且仅有一个定义。
声明(declaration)用于向程序表明变量的类型和名字。定义也是声明:当定义变量的时候我们声明了它的类型和名字。可以通过使用extern声明变量名而不定义它。不定义变量的声明包括对象名、对象类型和对象类型前的关键字extern。
extern声明不是定义,也不分配存储空间。事实上它只是说明变量定义在程序的其他地方。程序中变量可以声明多次,但只能定义一次。
只有当声明也是定义时,声明才可以有初始化式,因为只有定义才分配存储空间。初始化式必须要有存储空间来进行初始化。如果声明有初始化式,那么它可被当作是定义,即使声明标记为extern。
任何在多文件中使用的变量都需要有与定义分离的声明。在这种情况下,一个文件含有变量的定义,使用该变量的其他文件则包含该变量的声明(而不是定义)。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
如何清晰的区分变量声明和定义
extern通知编译器变量在其他地方被定义
1.extern告诉编译器变量在其他地方定义了。
例如:
extern int i; //声明,不是定义
int i; //声明,也是定义,未初始化
- 1
- 2
带有初始化式的声明必定式定义
2.如果声明有初始化式,就被当作定义,即使前面加了extern。
只有当extern声明位于函数外部时,才可以被初始化。
例如:
extern double pi=3.141592654; //定义
- 1
函数的声明和定义
3.函数的声明和定义区别比较简单,带有{ }的就是定义,否则就是声明。
例如:
extern double max(double d1,double d2); //声明
- 1
除非有extern关键字,否则都是变量的定义。
4.除非有extern关键字,否则都是变量的定义。
例如:
extern int i; //声明
int i; //定义
- 1
- 2
程序模块化设计风格
概要
1. 不要把变量定义放入.h文件,这样容易导致重复定义错误。
永远不要在.h文件中定义变量。定义变量和声明变量的区别在于定义会产生内存分配的操作,是汇编阶段的概念;而声明则只是告诉包含该声明的模块在连接阶段从其它模块寻找外部函数和变量
2. 尽量使用static关键字把变量定义限制于该源文件作用域,除非变量被设计成全局的。
3. 可以在头文件中声明一个变量,在用的时候包含这个头文件就声明了这个变量。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
模块化要点
(1) 模块即是一个.c文件和一个.h文件的结合,头文件(.h)中是对于该模块接口的声明;
(2) 某模块提供给其它模块调用的外部函数及数据需在.h中文件中冠以extern关键字声明;
(3) 模块内的函数和全局变量需在.c文件开头冠以static关键字声明;
(4) 永远不要在.h文件中定义变量!定义变量和声明变量的区别在于定义会产生内存分配的操作,是汇编阶段的概念;而声明则只是告诉包含该声明的模块在连接阶段从其它模块寻找外部函数和变量。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
一般情况下头文件中只放变量的声明,因为头文件要被其他文件包含(即#include),如果把定义放到头文件的话,就不能避免多次定义变量,C++不允许多次定义变量,一个程序中对指定变量的定义只有一次,声明可以无数次。
不过有三个例外,一下三中实体的定义也可放到头文件中。
1.值在编译时就已知的const 变量的定义可以放到头文件中
如:const int num(10);
2.类的定义可以放到头文件中
3.inline 函数
- 1
- 2
- 3
- 4
- 5
这三个实体可以定义在多个源文件中,只要在每个源文件中的定义相同。
示例程序
#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;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
在这个程序中,我们再函数外部定义了一个变量
注extern int a = 10;只有当extern声明位于函数外部时,才可以被初始化。
我们后面还会提到这个问题
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int a; // 定义一个变量, 不初始化
int b = 10; // 定义一个变量, 同时进行初始化
extern int c; // 声明一个外部extern的int型变量a
printf("a = %d\n", a);
printf("b = %d\n", b);
printf("c = %d\n", c);
extern int d = 10;
return EXIT_SUCCESS;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
在这个程序中,
int a;是个定义,但是未初始化,打印他的值式不确定的,因此编译时会报未初始化的异常。
int b = 10; 是个定义,并且被正确初始化,打印b的值没有问题。
但是是个声明,如果要对c进行读写操作,而我们并没有对c进行定义,因此语法检查没有问题,但是在链接时,连接器会找不到c的地址。
对于d再明显不过了,前面我们提到过如果声明有初始化式,就被当作定义,即使前面加了extern。但是只有当extern声明位于函数外部时,才可以被初始化。
现在这个定义很明显被gcc编译器认为是错误的。
C语言中声明和定义详解(待看。。的更多相关文章
- [C++] C++中的宏定义详解
转载自:C++中的宏定义 和 C++宏定义详解 一.#define解析 #define是C语言中提供的宏定义命令,其主要目的是为程序员在编程时提供一定的方便,并能在一定程度上提高程序的运行效率 ...
- Linux中THIS_MODULE宏定义详解
一直都在耿耿于怀,这个THIS_MODULE到底是个什么玩意,linux内核中无处不在的东西.今天上网搜了一下,算是基本明白了.网上牛人写的已经比较详细,另外目前暂时没有时间往更深层次分析,所以直接贴 ...
- HanLP中人名识别分析详解
HanLP中人名识别分析详解 在看源码之前,先看几遍论文<基于角色标注的中国人名自动识别研究> 关于命名识别的一些问题,可参考下列一些issue: l ·名字识别的问题 #387 l ·机 ...
- VS2010 Chart控件(一)Chart控件在ASP.NET网站中的应用示例详解(C#语言)
步骤如下: 1. Chart控件(一)Chart控件在ASP.NET网站中的应用示例详解(C#语言)" title="VS2010 Chart控件(一)Chart控件在ASP.NE ...
- Scala 深入浅出实战经典 第53讲:Scala中结构类型实战详解
王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...
- iOS中MVC等设计模式详解
iOS中MVC等设计模式详解 在iOS编程,利用设计模式可以大大提高你的开发效率,虽然在编写代码之初你需要花费较大时间把各种业务逻辑封装起来.(事实证明这是值得的!) 模型-视图-控制器(MVC)设计 ...
- Asp.net中web.config配置文件详解(一)
本文摘自Asp.net中web.config配置文件详解 web.config是一个XML文件,用来储存Asp.NET Web应用程序的配置信息,包括数据库连接字符.身份安全验证等,可以出现在Asp. ...
- Go语言Slice作为函数参数详解
Go语言Slice作为函数参数详解 前言 首先要明确Go语言中实质只有值传递,引用传递和指针传递是相对于参数类型来说. 个人认为上诉的结论不对,把引用类型看做对指针的封装,一般封装为结构体,结构体是值 ...
- JS中的event 对象详解
JS中的event 对象详解 JS的event对象 Event属性和方法:1. type:事件的类型,如onlick中的click:2. srcElement/target:事件源,就是发生事件的 ...
随机推荐
- Python学习笔记(socket)
socket(数据传输接口) 搭建服务端 1.导入模块 import socket 2.创建socket对象 sock=socket .socket(socket_family,socket_topy ...
- 剑指Offer的学习笔记(C#篇)-- 跳台阶
题目描述 一只青蛙一次可以跳上1级台阶,也可以跳上2级.求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果). 一 . 解题思路. 由题目可知,青蛙一次可以跳一阶或者两阶.假设台阶为 ...
- eosiolib文件解析
Source base on EOS version: 1.0.5,some photo except. 在eos源码中,eosiolib库在源码中的位置如下: 在\eos\contracts\e ...
- Python web前端 10 bootstrp
Python web前端 10 bootstrp 1.媒体查询 <style> *{ margin: 0; padding: 0; } div{ width: 110px; height: ...
- Java选择排序算法
package com.jckb; /**选择排序 * * @author gx *算法原理: *第一个数和后面每个数进行比较,如果大于后面的数就进行位置交换, *第一次比较结束后得到了最小值 */ ...
- gulp管理angular2项目 配置文件
目录结构: projectName |_ src |_ app |_ index.html |_ main.ts |_ systemjs.config.js |_ gulpfile.js |_ pac ...
- 多线程----Thread类,Runnable接口,线程池,Callable接口,线程安全
1概念 1.1进程 进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 任务管理器中: 1.2线程 线程是进程中的一个执行单元 ...
- 记录:swift学习笔记1-2
swift还在不断的更新做细微的调整,都说早起的鸟儿有虫吃,那么我们早点出发吧,趁着国内绝大多数的coder们还没有开始大范围普遍应用. 网上有些大神说:swift很简单!我不同意这个观点,假如你用h ...
- java 使用uuid生成唯一字符串
UUID(Universally Unique Identifier)全局唯一标识符,是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的.按照开放软件基金会(OSF)制定的标准计算, ...
- 使用jQuery发送ajax
我们先看一下js的原生ajax 直接进入代码,我们先准备好servlet,之后不会改动,所以先看一下. package cn.curry.servlet; import com.alibaba.fas ...