zoukankan      html  css  js  c++  java
  • 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文件中。 
    
    
    test.h
    #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预编译文件
    
    # 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头文件去除,否则会在编译过程中出现重定义错误。 
    
    一些思考:
    1、.h头文件的作用只出现在预编译阶段,预编译后.h文件就失去了价值,也就是说一个.cpp文件为一个编译单元,一个.cpp文件最终生成一个.o文件
    2、.h头文件应该包含些什么?
    a. 包含声明、条件预编译指令以及类的定义(类的定义一定要有条件预编译指令,否则多个文件包含会出现重定义错误)
    b. 包含需要的的头文件,无关的头文件都不需要包含,cpp使用的头文件都放入cpp文件中,或者单独建立一个总体的头文件包含所有需要使用的头文件
    c. 包含常量(包括const常量声明,定义放在源文件中)和宏定义 
    
    
    
    
    在头文件中定义变量或函数会出现什么问题?(全局变量和函数默认是extern属性) 
    
    
    local_comm.h
    
    #ifndef _LOCAL_H 
    #define _LOCAL_H 
    int var = 2; 
    void func() {}; 
    #endif 
    test1.cpp
    
    #include <stdio.h> 
    #include "local_comm.h" 
     
    void func1()  
    { 
            printf("func1 &var=%lu
    ", &var);   
    } 
    test2.cpp
    
    #include <stdio.h> 
    #include "local_comm.h" 
     
    void func2()  
    { 
            printf("func2 &var=%lu
    ", &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全局变量时,都把它放在原文件中而不是头文件,这样就不会给其他模块造成不必要的信息污染。 
    
    转:http://my.oschina.net/fergus/blog/123484 
  • 相关阅读:
    用户自定义控件的嵌套问题
    ASP.NET进阶:调用Javascript
    [网络收集]FCKeditor配置和精简【附源码】
    检查session判断用户是否退出登录
    Server.Transfer VS Response.Redirect
    asp.net下ckeditor3.0.1和ckfinder_aspnet_1.4.1.1的配置方法
    Sudoku(数独)
    转自:蓝色污点的专栏
    LETTERS(字母)
    放苹果
  • 原文地址:https://www.cnblogs.com/zendu/p/4981474.html
Copyright © 2011-2022 走看看