头文件作用 以及 声明与定义的区别
2011-03-31 23:52
274 查看
C++/C 编译器 在扫描到一条【函数调用】语句时首先
应当知道该 函数的原型
或 定义
。
// 即,读到这条语句之前,应该已经出现过函数的声明(或者定义)。这样编译器才知道这是个函数,然后通过指针跳转到存储函数的内存区间。
函数原型一般都放在头文件中,函数定义则放在源文件中
当源文件或头文件通过#include指令包含另一个头文件的时候,编译预处理器
用头文件的内容代#include伪指令。这就是说,头文件的所有内容最终都会被合并到某一个或某几个源文件中,如此将每一个包含的头文件递归地展开后形成
的源文件就叫编译单元
。
// 通过改变连接性( extern/static ),
可以
使
一个编译单元
中 函数和变量 让其他编译单元使用。
声明只是告诉编译器,叫XXX的是个变量或者是个函数
。你要用,还得找定义在哪。
定义是具体实现,会在.o文件中生成符号
。
函数和变量都默认外部连接性(所有编译单元都能看到,这里有一个叫做XXX的变量或函数的导出符号,比如_XXX)。
连接时,这个编译单元需要什么符号 (声明说了,这个XXX是个函数,但自己没有定义,只能去别的地方找
),就从别的编译单元导出的符号里找。
因此,头文件里声明一个函数,一般都只是声明。很多cpp都会include它,然后cpp就知道了叫XXX的是个函数,但是发现自己这里没定义,再去别的cpp里找。
// 如果 .h 里放了定义,有两个cpp文件都include这个.h, 一连接,这个定义就出现了两次(冒出两个一样的符号
duplicated external simbols
)。
所以,对于外部连接性的东西(函数和变量),声明可以每个文件里都有,但是定义只能有一个
!
头文件用途:
通过头文件来调用库功能。源代码不便向用户公布,只
要向用户提供
头文件
和
二进制的库
即可。头文件中找接口声明,然后调用库函数。连接器会从库中提取相应的代码,并和用户的程序连接生成可执行文件 或者 动态连接库文件。
头文件能加强类型安全检查。接口被实现的方式与头文件中的声明不一致,编译器就会指出错误。
【头文件的内容】:
(1)头文件注释(包括文件说明、功能描述、版权声明等)(必须有);
(2)内部包含卫哨开始(#ifndef XXX/#define XXX)(必须有);
(3)#include其他头文件(如果需要);
(4)外部变量和全局函数声明(如果需要);
(5)常量和宏定义(如果需要);
(6)类型前置声明和定义(如果需要);
(7)全局函数原型和内联函数的定义(如果需要);
(8)内部包含卫哨结束:#endif // XXX(必须有);
(9)文件版本及修订说明。
如果程序中需要内联函数,那么内联函数的定义应当放在头文件中,因为内联函数调用语句最终被扩展开来而不是采用真正的函数调用机制。
应当知道该 函数的原型
或 定义
。
// 即,读到这条语句之前,应该已经出现过函数的声明(或者定义)。这样编译器才知道这是个函数,然后通过指针跳转到存储函数的内存区间。
函数原型一般都放在头文件中,函数定义则放在源文件中
当源文件或头文件通过#include指令包含另一个头文件的时候,编译预处理器
用头文件的内容代#include伪指令。这就是说,头文件的所有内容最终都会被合并到某一个或某几个源文件中,如此将每一个包含的头文件递归地展开后形成
的源文件就叫编译单元
。
// 通过改变连接性( extern/static ),
可以
使
一个编译单元
中 函数和变量 让其他编译单元使用。
声明只是告诉编译器,叫XXX的是个变量或者是个函数
。你要用,还得找定义在哪。
定义是具体实现,会在.o文件中生成符号
。
函数和变量都默认外部连接性(所有编译单元都能看到,这里有一个叫做XXX的变量或函数的导出符号,比如_XXX)。
连接时,这个编译单元需要什么符号 (声明说了,这个XXX是个函数,但自己没有定义,只能去别的地方找
),就从别的编译单元导出的符号里找。
因此,头文件里声明一个函数,一般都只是声明。很多cpp都会include它,然后cpp就知道了叫XXX的是个函数,但是发现自己这里没定义,再去别的cpp里找。
// 如果 .h 里放了定义,有两个cpp文件都include这个.h, 一连接,这个定义就出现了两次(冒出两个一样的符号
duplicated external simbols
)。
所以,对于外部连接性的东西(函数和变量),声明可以每个文件里都有,但是定义只能有一个
!
test.h: extern int a; // 变量的声明就是定义!变量声明的时候就会分配内存。 // 虽然默认外部连接性,但是放在头文件里会被很多cpp包含,就会重复定义了。 所以必须加一个 extern 明确告诉编译器,a在别的地方定义。 void func(); test1.cpp #include "test.h" int a=123 // a 的赋值在这里 void func() // func的实现 { print("test"); } main.cpp #include "test.h" // int a=1234; // cpp文件中,定义的全局变量,由于外部链接性,再别的文件中也可访问。 main() { func(); // 从.h中编译器知道,func是个函数。自己这里没找到定义,从test1.cpp中找到了。 }
头文件用途:
通过头文件来调用库功能。源代码不便向用户公布,只
要向用户提供
头文件
和
二进制的库
即可。头文件中找接口声明,然后调用库函数。连接器会从库中提取相应的代码,并和用户的程序连接生成可执行文件 或者 动态连接库文件。
头文件能加强类型安全检查。接口被实现的方式与头文件中的声明不一致,编译器就会指出错误。
【头文件的内容】:
(1)头文件注释(包括文件说明、功能描述、版权声明等)(必须有);
(2)内部包含卫哨开始(#ifndef XXX/#define XXX)(必须有);
(3)#include其他头文件(如果需要);
(4)外部变量和全局函数声明(如果需要);
(5)常量和宏定义(如果需要);
(6)类型前置声明和定义(如果需要);
(7)全局函数原型和内联函数的定义(如果需要);
(8)内部包含卫哨结束:#endif // XXX(必须有);
(9)文件版本及修订说明。
如果程序中需要内联函数,那么内联函数的定义应当放在头文件中,因为内联函数调用语句最终被扩展开来而不是采用真正的函数调用机制。
相关文章推荐
- c++中的声明和定义的区别,以及关键字extern的作用
- linux c 一站式学习 extern关键词作用、变量的声明与定义以及extern与include的区别(都与extern有关)
- c++高级---C++声明、定义、类的定义、头文件作用、头文件重复引用,不具名空间以及编译器编译链接过程
- 为什么同样是pom文件里面的架包jar,显示的图标不一样。以及maven中snapshot快照库和release发布库的区别和作用
- C++ 关于声明,定义,类的定义,头文件作用,内、外链接
- JS特权方法定义作用以及与公有方法的区别
- 详解keil采用C语言模块化编程时全局变量、结构体的定义、声明以及头文件包含的处理方法!
- C++ 关于声明,定义,类的定义,头文件作用,防止头文件在同一个编译单元重复引用,不具名空间
- 详解keil采用C语言模块化编程时全局变量、结构体的定义、声明以及头文件包含的处理方法
- C++ 关于声明,定义,类的定义,头文件作用,防止头文件在同一个编译单元重复引用,不具名空间
- 详解keil采用C语言模块化编程时全局变量、结构体的定义、声明以及头文件包含的处理方法!
- 定义和声明的区别,它们在头文件、源文件中的位置,extern的用法
- keil 中——C语言模块化编程时全局变量、结构体的定义、声明以及头文件包含的处理方法
- C/C++ 变量声明和定义的区别 静态变量的作用
- C++声明、定义、类的定义、头文件作用、头文件重复引用
- C++ 关于声明,定义,类的定义,头文件作用,防止头文件在同一个编译单元重复引用,不具名空间
- C++ : 编译单元、声明和定义、头文件作用、防止头文件在同一个编译单元重复引用、static和不具名空间
- C++ 关于声明,定义,类的定义,头文件作用,防止头文件在同一个编译单元重复引用,不具名空间
- 变量的声明与定义以及区别
- C++ 关于声明,定义,类的定义,头文件作用,不具名空间