C++中头文件、源文件之间的区别与联系

.h头文件和.cpp文件的区别
疑惑1:.h文件可以编写main函数吗?
实验:
编写test.h文件,里面包含main函数
若直接编译g++ test.h -o test,经过file命令 file test,获得以下结果test: GCC precompiled header (version 013) for C++ ———test文件是预编译头文件

推测:.h文件不能单独生成.o文件 函数

疑惑2:.h文件中声明和定义的变量和函数是如何与.cpp文件结合的?
实验:
编写test.h文件,里面包含一个变量定义以及函数定义,编写test.cpp文件包含该头文件,经过g++ -E test.cpp -o test.i生成预编译文件,打开test.i文件发现,上面包含了头文件中变量的定义以及函数的定义,就像平时咱们能够不写.h文件,只写.cpp文件同样,把全部的声明和定义都放在了一个.cpp文件中。
ui

test.h spa

#ifndef _TEST_H
#define _TEST_H
int var = 1;
void func {

}
#endif
test2.h
#ifndef _TEST2_H
#define _TEST2_H
#include "test.h"
#endif
test.cpp
#include "test.h"
#include "test2.h"

int main ()
{
    var = 2;
    return 0;
}

gcc -E test.cpp -o test.i 获得test.i预编译文件 code

# 1 "test.cpp"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "test.cpp"
# 1 "test.h" 1


int var = 1;
void func {

}
# 2 "test.cpp" 2
# 1 "test2.h" 1
# 3 "test.cpp" 2

int main () 
{
    var = 2;
    return 0;
}

推测:.cpp文件中的#include预编译指令将.h的文件内容包含进来(#include指令是递归执行的),并经过条件预编译指令#ifndef、#define、#endif将重复的.h头文件去除,不然会在编译过程当中出现重定义错误。 递归

一些思考:
一、.h头文件的做用只出如今预编译阶段,预编译后.h文件就失去了价值,也就是说一个.cpp文件为一个编译单元,一个.cpp文件最终生成一个.o文件
二、.h头文件应该包含些什么?
a. 包含声明、条件预编译指令以及类的定义(类的定义必定要有条件预编译指令,不然多个文件包含会出现重定义错误)
b. 包含须要的的头文件,无关的头文件都不须要包含,cpp使用的头文件都放入cpp文件中,或者单独创建一个整体的头文件包含全部须要使用的头文件
c. 包含常量(包括const常量声明,定义放在源文件中)和宏定义
ip


在头文件中定义变量或函数会出现什么问题?(全局变量和函数默认是extern属性) 作用域

local_comm.h it

#ifndef _LOCAL_H
#define _LOCAL_H
int var = 2;
void func() {};
#endif

test1.cpp io

#include <stdio.h>
#include "local_comm.h"

void func1() 
{
        printf("func1 &var=%lu\n", &var);  
}
test2.cpp
#include <stdio.h>
#include "local_comm.h"

void func2() 
{
        printf("func2 &var=%lu\n", &var);  
}
main.cpp
extern void func1();
extern void func2();
int main()
{
        func1();
        func2();
}
g++ main.cpp test1.cpp test2.cpp 编译报错
$g++ main.cpp test1.cpp test2.cpp 
/tmp/ccGkEzQE.o: In function `func()':
test2.cpp:(.text+0x0): multiple definition of `func()'
/tmp/ccpTecbJ.o:test1.cpp:(.text+0x0): first defined here
/tmp/ccGkEzQE.o:(.data+0x0): multiple definition of `var'
/tmp/ccpTecbJ.o:(.data+0x0): first defined here
collect2: ld returned 1 exit status
结论:头文件的条件预编译指令只能去掉同一个编译单元中包含的重复定义,不能在连接的时候去掉各个编译单元中的相同的定义,由于普通变量和函数默认属性是全局的,也就是在整个最后生成的exe中只能有惟一一个同名的变量和函数。


在头文件中定义static静态变量或者静态函数会出现什么问题?(全局const变量默认是static属性) 编译

修改local_comm.h,将变量和函数改为static属性。

#ifndef _LOCAL_H
#define _LOCAL_H
static int var = 2;
static void func() {};
#endif

编译运行:

$g++ main.cpp test1.cpp test2.cpp
$./a.out
func1 &var=4196096
func2 &var=4196116
结论:静态变量和静态函数的做用域只是在本编译单元(.o文件),在不一样的副本都保存了该静态变量和静态函数,正是由于static有以上的特性,因此通常定义static全局变量时,都把它放在原文件中而不是头文件,这样就不会给其余模块形成没必要要的信息污染。
相关文章
相关标签/搜索