1.变量的定义&声明

变量的声明有两种情况:

<1>一种是需要建立存储空间的。例如:int a 在声明的时候就已经建立了存储空间。

<2>另一种是不需要建立存储空间的。 例如:extern int a 其中变量a是在别的文件中定义的。

前者是“定义性声明(defining declaration)”或者称为“定义(definition)”,而后者是“引用性声明(referncing declaration)”。

从广义的角度来讲声明中包含着定义,即定义是声明的一个特例,所以并非所有的声明都是定义,例如:int a 它既是声明,同时又是定义。然而对于 extern a 来讲它只是声明不是定义。

一般的情况下我们常常这样叙述,把建立空间的声明称之为“定义”,而把不需要建立存储空间的声明称之为“声明”。很明显我们在这里指的声明是范围比较窄的,即狭义上的声明,也就是说非定义性质的声明,例如:在主函数中:

int main()
{
extern int A;
//这是个声明而不是定义,声明A是一个已经定义了的外部变量
//注意:声明外部变量时可以把变量类型去掉如:extern
A;
dosth();//执行函数
}

int A; //是定义,定义了A为整型的外部变量

外部变量的“定义”与外部变量的“声明”是不相同的,外部变量的定义只能有一次,它的位置是在所有函数之外,而同一个文件中的外部变量声明可以是多次的,它可以在函数之内(哪个函数要用就在那个函数中声明)也可以在函数之外(在外部变量的定义点之前)。系统会根据外部变量的定义(而不是根据外部变量的声明)分配存储空间的。对于外部变量来讲,初始化只能是在“定义”中进行,而不是在“声明”中。所谓的“声明”,其作用,是声明该变量是一个已在后面定义过的外部变量,仅仅是为了“提前”引用该变量而作的“声明”而已。extern
只作声明,不作任何定义。

(我们声明的最终目的是为了提前使用,即在定义之前使用,如果不需要提前使用就没有单独声明的必要,变量是如此,函数也是如此,所以声明不会分配存储空间,只有定义时才会分配存储空间。)

注:如果声明有初始化式,那么它可以被当作是定义,即使声明标记为extern:

  extern double pi=3.1416; //定义

  虽然使用了extern,但这条语句还是定义了pi,分配并初始化了存储空间。只有当extern声明位于函数外部时,才可以含有初始化式。

任何在多个文件中使用的变量都需要有与定义分离的声明。在这种情况下,一个文件含有变量的定义,使用该变量的其他文件则包含该变量的声明(而不是定义)。

用static来声明一个变量的作用有二:

(1)对于局部变量用static声明,则是为该变量分配的空间在整个程序的执行期内都始终存在。

(2)外部变量用static来声明,则该变量的作用只限于本文件模块。

2.函数的定义&声明

声明:一般在头文件里,对编译器说:这里我有一个函数叫function() 让编译器知道这个函数的存在。声明是告诉编译器有这么个变量,但并不实现。

定义:就是实现这个变量,真正在内存(堆或栈中)为此变量分配空间。定义一般在源文件里,具体就是函数的实现过程,写明函数体。

对函数的“定义”和“声明”不是一回事。“定义”是指对函数功能的确立,包括指定函数名,函数值类型、形参类型、函数体等,它是一个完整的、独立的函数单位。而“声明” 的作用则是把函数的名字、函数类型以及形参类型、个数和顺序通知编译系统,以便在调用该函数时系统按此进行对照检查(例如函数名是否正确,实参与形参的类型和个数是否一致)。

从程序中可以看到对函数的声明与函数定义中的函数首部基本上是相同的。因此可以简单地照写已定义的函数的首部,再加一个分号,就成为了对函数的“声明”。在函数声明中也可以不写形参名,而只写形参的类型。

在C语言中,函数声明称为函数原型(function prototype)。使用函数原型是ANSI C的一个重要特点。它的作用主要是利用它在程序的编译阶段对调用函数的合法性进行全面检查。

说明:

<1> 以前的C版本的函数声明方式不是采用函数原型,而只是声明函数名和函数类型。 如:float add(); 不包括参数类型和参数个数。系统不检查参数类型和参数个数。新版本也兼容这种用法,但不提倡这种用法,因为它未进行全面的检查。

<2> 实际上,如果在函数调用前,没有对函数作声明,则编译系统会把第一次遇到的该函数形式(函数定义或函数调用)作为函数的声明,并将函数类型默认为int 型。如一个max函数,调用之前没有进行函数声明,编译时首先遇到的函数形式是函数调用"max(a, b)",由于对原型的处理是不考虑参数名的,因此系统将max()加上int作为函数声明,即int max(); 因此不少教材说,如果函数类型为整型,可以在函数调用前不必作函数声明。但是使用这种方法时,系统无法对参数的类型做检查。或调用函数时参数使用不当,在编译时也不会报错。因此,为了程序清晰和安全,建议都加以声明为好。

<3> 如果被调用函数的定义出现在主调函数之前,可以不必加以声明。因为编译系统已经先知道了已定义的函数类型,会根据函数首部提供的信息对函数的调用作正确性检查。

<4> 如果已在所有函数定义之前,在函数的外部已做了函数声明,则在各个主调用函数中不必对所调用的函数再作声明。

3.C语言中头文件和源文件写法有什么区别?

相同点: 头文件与源代码都是源文件,都用纯文本文件存储,都需要遵照C/C++语言规范来写,都可以使用类型定义和常、变量定义,都可以包含函数的声明和实现,都能包含宏定义,都使用相同的调用规范。

不同点: C/C++的编译器规定源代码文件必须包含函数入口,即main函数,或者winmain函数。而头文件不得包含函数入口,也就是说,头文件不可以单独编译成一个程序,仅仅包含程序片断或者仅仅定义常、变量。

关联: 头文件是专为源代码调用而写的静态包含文件,可被源代码文件中的#include编译预处理指令解释,而将头文件完整拷贝到源代码的指令处,从而在编译时相当于在源代码中插入了函数声明或者实现。

某些头文件包含了静态库中的函数调用声明,包含了LIB文件的调用信息,编译时静态链接进程序;而某些头文件是专为方便API调用而写的,里面包含了动态链接库的调用信息和规范,只有在运行时将DLL载入内存提取函数执行。

也就是说,其实你将头文件里的信息完全写到源代码里,是可以实现完全相同的功能的。如果你想要学写头文件,可以参照标准C/C++库的h文件。

C语言——定义&&声明的更多相关文章

  1. 【非原】c语言之声明和定义的区别

    原创地址:http://www.cnblogs.com/haore147/p/3647466.html 什么是定义?什么是声明?它们有何区别? 举个例子: 1 2 A)int i; B)extern  ...

  2. 陈正冲老师讲c语言之声明和定义的区别

    什么是定义?什么是声明?它们有何区别? 举个例子: A)int i; B)extern int i;(关于extern,后面解释) 哪个是定义?哪个是声明?或者都是定义或者都是声明?我所教过的学生几乎 ...

  3. 《C专家编程》第三章——分析C语言的声明

    前面一章我们已经说过C语言存在的一些问题和它晦涩的地方,让我们对这门神奇的语言有了更深的了解.现在这一章则集中精力来讨论C语言的声明,分为三块,首先是说明C语言声明晦涩难懂的原因和声明是如何形成的,其 ...

  4. C语言字符串声明

    重新学习C语言字符串声明char *a="nihao";char a[]="nihao";什么区别?前者定义的是指针,并且指向字符串常量“nihao”,后者是字 ...

  5. c语言复杂声明解析

    这是个好东西,接触c语言好几年了,第一次看到这东西,惊喜万分. 先提供个分析案例,以后看方便 vector <int> * (*seq_array[]) (int )={func1,fun ...

  6. C++语言定义的标准转换

    标准转换 C++ 语言定义其基础类型之间的转换. 它还定义指针.引用和指向成员的指针派生类型的转换. 这些转换称为“标准转换. 1. 整型提升 整数类型的对象可以转换为另一个更宽的整数类型(即,可表示 ...

  7. [日常] go语言圣经-声明,变量,赋值,类型,包和文件习题

    go语言圣经-声明1.四种类型的声明语句:var.const.type和func,分别对应变量.常量.类型和函数实体对象的声明2.包一级声明语句声明的名字可在整个包对应的每个源文件中访问,局部声明的名 ...

  8. C语言复杂声明-void (*signal(int sig, void (*handler)(int)))(int);

    问题提出 请分析此声明:void (*signal(int sig, void (*handler)(int)))(int); 求解过程 在对上面的例子作分析之前,我们需要了解C语言的声明优先级,&l ...

  9. C语言复杂声明

    C语言复杂声明 First step int *f(); /* f:是一个函数,它返回一个指向int类型的指针*/ int (*pf)(); /* pf:是一个指向函数的指针,该函数返回一个int类型 ...

随机推荐

  1. 2749: [HAOI2012]外星人

    首先像我一样把柿子画出来或者看下hint 你就会发现其实是多了个p-1这样的东东 然后除非是2他们都是偶数,而2就直接到0了 算一下2出现的次数就好 #include<cstdio> #i ...

  2. poj--1101--The Game(bfs)

    The Game Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 9746   Accepted: 2967 Descript ...

  3. B3300 [USACO2011 Feb]Best Parenthesis 模拟

    这是我今天遇到最奇怪的问题,希望有人帮我解释一下... 一开始我能得90分: #include<iostream> #include<cstdio> #include<c ...

  4. 洛谷P1894 [USACO4.2]完美的牛栏The Perfect Stall(二分图)

    P1894 [USACO4.2]完美的牛栏The Perfect Stall 题目描述 农夫约翰上个星期刚刚建好了他的新牛棚,他使用了最新的挤奶技术.不幸的是,由于工程问题,每个牛栏都不一样.第一个星 ...

  5. weui&flexible布局

    1.weui 一开始以为只能用于小程序中,原来分两种:weui-wxss-master和weui-master.真的是强大的不得了,把设计好的样式和功能封装.然后分类,有明确的层级和逻辑,感动!!值得 ...

  6. POJ 3322 Bloxorz I

    首先呢 这个题目的名字好啊 ORZ啊 如果看不懂题意的话 请戳这里 玩儿几盘就懂了[微笑] http://www.albinoblacksheep.com/games/bloxorz 就是这个神奇的木 ...

  7. SpringMVC参数绑定(二)

    在springMVC中,提交请求的数据是通过方法形参来接收的,从客户端请求的key/value数据,经过参数绑定,将key/value数据绑定到controller形参上,然后再controller就 ...

  8. Laravel5.1学习笔记5 请求

    HTTP 请求 #取得请求实例 #基本的请求信息 #PSR-7 请求 #取出输入数据 #旧的输入 #Cookies #文件 #取得请求实例(此部分文档5.1完全重写,注意) 要通过依赖注入获取当前HT ...

  9. MSP430之section(1)

    1 Intro The smallest unit of an object file is a section. A section is a block of code or data that ...

  10. Dispatch Queues and Thread Safety

    Dispatch Queues and Thread Safety It might seem odd to talk about thread safety in the context of di ...