C語言中文件包含.c文件、.h文件與直接多文件的區別與應用總結

  咱們一般在完成一個程序時,每每習慣將程序寫爲多文件的,這樣就能實現程序的模塊化管理,以及分工開發合做。而一些全局變量,全局函數,結構體等就能使各模塊聯繫在一塊兒。模塊化

  在日常你們寫代碼的過程當中,一般會使用文件包含來聯繫各代碼文件,固然初學者也可能會直接寫成多文件程序,沒有文件包含,這樣也能編譯、運行。函數

  在這裏,寫了一些小段的測試代碼,來講明:包含.c文件,,直接多文件,包含.h文件三種方式的區別與應用。測試

1.包含.c文件spa

  可能有人不習慣寫.h文件,而直接將代碼寫在.c文件中,其餘文件要調用函數則直接包含.c文件。正以下面一段代碼:code

//fun.c
int h = 0;
int cal(int a, int b)
{
    return (2*a+3*b);
}


//main.c
#include "stdio.h"
#include "fun.c"   //包含.c文件
int main(void)
{
    h = 1;   //直接使用fun.c中的變量
    int i = 1,j = 2;
    int c = 0;
    c = cal(i, j);  //直接調用fun.c中的函數
    printf("%d\n", c);
    return 0;
}

        編譯:gcc main.c -o main     直接編譯經過,運行正確。對象

咱們再看一個測試程序:blog

//fun.c
int h = 0;
int cal(int a, int b)
{
    return (2*a+3*b);
}

//fun1.c
#include "fun.c"   // 就這一句

//main.c
#include "stdio.h"
#include "fun.c"   //包含.c文件
#include "fun1.c"   //添加包含fun1.c
int main(void)
{
    h = 1;   //直接使用fun.c中的變量
    int i = 1,j = 2;
    int c = 0;
    c = cal(i, j);  //直接調用fun.c中的函數
    printf("%d\n", c);
    return 0;
}

       編譯:gcc main.c -o main   編譯報錯:h  cal  發生了重定義。開發

總結:io

        優勢能夠直接編譯main.c文件,不用編譯fun.c,由於在main.c的編譯預處理階段,會將fun.c 的代碼直接拷貝過來。讀者可使用gcc -E main.c -o main.i  查看預處理後.i文件的代碼。發現main.i中將fun.c的代碼拷貝了過來。編譯

   缺點:fun.c不能被多個文件包含,由於這樣就會產生變量和函數的多個拷貝,形成嚴重的重定義,編譯通不過。

        這種方式可解決較簡單程序的文件包含問題,一般不推薦使用。

2.直接多文件

       多文件程序中,全局變量能夠被外部引用,函數也默認是全局函數,能夠被外部使用。廢話少說,先上代碼:

//fun.c
int global_var = 0;

int cal(int a, int b)
{
    return (2*a+3*b);
}

//main.c
#include "stdio.h"

extern int  global_var;  // 聲明外部變量

int main(void)
{
    global_var =1;  //外部變量賦值
    int i = 1,j = 2;
    int c = 0;
    c = cal(i, j);  //外部函數調用
    printf("%d\n", c);
    return 0;
}

Makefile書寫爲:

CFLAG=-Wall -O -g

main:main.o fun.o
gcc $(CFLAG) main.o fun.o -o main
main.o:main.c
gcc $(CFLAG) -c main.c -o main.o
fun.o:fun.c
gcc $(CFLAG) -c fun.c -o fun.o
clean:
rm main.o fun.o main

編譯經過,會出現警告信息,說cal爲隱含的外部函數。運行正確。結果還算理想,那麼咱們再來看一段:

 1 int global_var = 0;
 2 struct student
 3 {
 4     int age;
 5     int num;
 6 };                     //定義結構體
 7 struct student wang;     //定義結構體變量
 8 int cal(int a, int b)
 9 {
10     return (2*a+3*b);
11 }
12 
13 #include "stdio.h"
14 extern int  global_var;
15 extern struct student wang;   //聲明外部結構體變量
16 int main(void)
17 {
18     wang.age = 10;  //報錯
19     student li;    //想使用外部的定義的結構體來定義一個變量   報錯
20     global_var =1;
21     int i = 1,j = 2;
22     int c = 0;
23     c = cal(i, j);
24     printf("%d\n", c);
25     return 0;
26 }

一樣的編譯,main.c文件的編譯會出現錯誤,首先是想使用外部定義的結構體變量(已做聲明),報錯。而後,想用外部結構體定義一個變量,報錯。

總結:

  優勢不會出現重定義問題

  缺點一、若是要用到的外部變量多,或是在多處要使用外部變量,則要在每個調用的文件中使用extern聲明,比較麻煩。

       二、若是是在fun.c中有結構體定義或是類的定義,在main.c中用使用結構體定義變量,或是使用類定義對象。編譯不能經過,不知該如何處理。

       三、若是是定義在fun.c中的結構體變量,在main.c中要聲明外部變量,並使用,會出錯。故推知:結構體不能聲明爲外部變量,只能是包含的頭文件中定義的結構體。

解決上述問題的方式就是第三種,包含.h文件方式。

3.包含.h文件

  爲每個模塊都編寫一個.c文件,一個.h文件。

  .c源文件中放:函數的定義,全局變量的定義,全局結構體變量的定義。

  .h頭文件中放:函數的聲明,全局變量的聲明(extern),全局結構體的定義,全局結構體變量的聲明。

  調用文件(main.c)文件中:包含.h頭文件便可。不用聲明任何東西。

  測試代碼以下:

//fun.c
#include "fun.h"

int global_var = 0;

struct student wang;  //結構體變量定義

int cal(int a, int b)
{
    return (2*a+3*b);
}

//fun.h
#ifndef _fun_h_  //條件編譯,解決文件重複包含所引發的重定義問題
#define _fun_h_

struct student
{
    int age;
    int num;
};

extern int global_var;
extern struct student wang;

#endif

//fun1.c
#include "fun1.h"  //沒有實際代碼

//fun1.h
#include "fun.h"  //包含fun.h

//main.c
#include "stdio.h"
#include "fun.h"
#include "fun1.h"

//extern int  global_var;
//extern struct student wang;
int main(void)
{
    wang.age = 10;   //調用全局結構體變量
    struct student li;  //定義變量
    global_var =1;  //使用全局變量

    int i = 1,j = 2;
    int c = 0;
    c = cal(i, j);
    printf("%d\n", c);
    return 0;
}

 總結:

    優勢:解決了文件重複包含形成的重定義問題;函數,全局變量,結構體,結構體變量都能在外部調用;每一處調用變量的文件處不用重複的寫聲明語句,由於聲明語句直接寫在了.h頭文件中,直接包含頭文件便可。

相關文章
相關標籤/搜索