c語言的編譯過程:
而預處理中有三種情況:
宏就是預處理中的一種情況. 其實,宏的概念就是文本替換
宏的作用:
1.可維護性
2.可讀性
宏還有其他作用比如:程序調試跟蹤 等, 因為我也沒試過那些,這裡不寫那些了
宏定義:
1.不帶參數的宏定義
#define 標識符 字符串
2.帶參數的宏定義
#define 標識符(參數表) 字符串
注意:標識符一般大寫 ,
這裡將不會解答宏中包含特殊符號:#、##的問題.
1.不帶參數的宏:
源文件:C:\Users\Zero\Desktop\c\temp\macro.c
#include<stdio.h> #define PI 3.1415 //定義常量PI void main(){ printf("PI常量的值:%f",PI); }
結果:
原因:
宏是預編譯中的一種情況(我在前面也有說到), 而預編譯主要就是替換,宏就是文本替換
我們可以生成預編譯後的文件來查看:
執行dos命令:
打開文件預編譯後的文件macro.i文件:
由於加載預編譯後的文本很長,這裡我主要顯示main主函數這部分:
wint_t __attribute__((__cdecl__)) __attribute__ ((__nothrow__)) fgetwchar (void); wint_t __attribute__((__cdecl__)) __attribute__ ((__nothrow__)) fputwchar (wint_t); int __attribute__((__cdecl__)) __attribute__ ((__nothrow__)) getw (FILE*); int __attribute__((__cdecl__)) __attribute__ ((__nothrow__)) putw (int, FILE*); # 2 "macro.c" 2 void main(){ printf("PI常量的值:%f",3.1415); }
我們可以看到原來的”PI”不見了,被替換成了3.1415
2.帶參數的宏:
源文件:C:\Users\Zero\Desktop\c\temp\macro2.c
#include <stdio.h> #define AREA(x,y) x*y void main(){ int a=6; int b=5; int result; result=AREA(a+b,a-b); printf("result:%d",result); }
結果:
原因:
也許有人會認為”result=AREA(a+b,a-b)”的運算過程是這樣的:
result = (a+b)*(a-b) --> result= (6+5)(6-5) --> result=11
不過,很遺憾它並不是函數,AREA(x,y) 不是函數 ,它不是函數!!!
開始就說過,宏就是替換 ,追其本質, 這裡也是替換.
查看預編譯後的文件:
執行dos命令:
打開文件預編譯後的文件macro2.i , 主要顯示main函數部分:
wint_t __attribute__((__cdecl__)) __attribute__ ((__nothrow__)) fgetwchar (void); wint_t __attribute__((__cdecl__)) __attribute__ ((__nothrow__)) fputwchar (wint_t); int __attribute__((__cdecl__)) __attribute__ ((__nothrow__)) getw (FILE*); int __attribute__((__cdecl__)) __attribute__ ((__nothrow__)) putw (int, FILE*); # 2 "macro2.c" 2 void main(){ int a=6; int b=5; int result; result=a+b*a-b; printf("result:%d",result); }
我們發現原來的”AREA(a+b,a-b)”被替換成了“a+b*a-b”
result = (a+b)*(a-b) --> result= (6+5)(6-5) --> result=11
result=a+b*a-b –> result=6+5*6-5 –> result=31
因為是替換,並不是函數,所以最後的結果是31
關於宏的作用:
1.可維護性
源文件:C:\Users\Zero\Desktop\c\temp\effect.c
#include <stdio.h> #define PI 3.14 void main(){ printf("控制台輸出PI:%f\n",PI); printf("控制台輸出PI:%f\n",PI); printf("控制台輸出PI:%f\n",PI); printf("控制台輸出PI:%f\n",PI); printf("控制台輸出PI:%f\n",PI); printf("控制台輸出PI:%f\n",PI); printf("控制台輸出PI:%f\n",PI); printf("控制台輸出PI:%f\n",PI); printf("控制台輸出PI:%f\n",PI); printf("控制台輸出PI:%f\n",PI); }
比如:我們在控制台輸出10次PI的值, PI=3.14 , 後來,我發現3.14並不是我想要的結果,
我想要修改原來3.14的值, 改成3.1415 ,這個時候 我只需要修改PI這個常量就可以了.並不需要修改10次
#include <stdio.h> #define PI 3.1415 void main(){ printf("控制台輸出PI:%f\n",PI); printf("控制台輸出PI:%f\n",PI); printf("控制台輸出PI:%f\n",PI); printf("控制台輸出PI:%f\n",PI); printf("控制台輸出PI:%f\n",PI); printf("控制台輸出PI:%f\n",PI); printf("控制台輸出PI:%f\n",PI); printf("控制台輸出PI:%f\n",PI); printf("控制台輸出PI:%f\n",PI); printf("控制台輸出PI:%f\n",PI); }
2.可讀性
假如,一個常量為3.1415926, 你的代碼也很長的時候,去找3.1415926是非常麻煩的,
#define PI=3.1415926 , 你只需要找到PI就可以了
結構體
在實際問題中,一組數組往往具有不同的數據類型,這個時候就可以用到結構體
結構體:結構體是基本數組類型組成,裡面可以存在不同類型的變量.像java中對象
結構體定義的是一個類型, 就好像自己定義了整形(int)一樣
結構體的定義:
顯示聲明結構體:
struct 結構體名{
類型 變量名;
類型 變量名;
…
};
匿名聲明結構體:
struct {
類型 變量名;
類型 變量名;
…
}結構體變量;
下面我將演示,及說明結構體的聲明:
顯示聲明結構體:
源文件:C:\Users\Zero\Desktop\c\temp\struct.c
#include<stdio.h> #include <string.h> //導入strcpy()函數的頭文件 //顯示聲明結構體 struct stu{ char name[20]; //學生姓名 int age; //學生年齡 }; void main(){ //聲明結構體變量 struct stu student; //struct stu: 這裡是一個類型, student是一個變量 //賦值 strcpy(student.name,"張二"); //student.name="張二",寫法是錯誤的 //因為字符數組定義之後,是不能直接賦值的 ,不過,可以用strcpy()方法賦值 student.age=13; //控制台輸出 printf("student.name:%s\n",student.name); printf("student.name:%d\n",student.age); }
編譯文件:
兩者的定義都是差不多的。關於訪問結構體裡的變量 ,一般都是通過 “結構體變量.變量” 訪問
匿名聲明結構體:
源文件:C:\Users\Zero\Desktop\c\temp\struct2.c
#include<stdio.h> #include <string.h> //導入strcpy()函數的頭文件 //匿名聲明結構體 struct{ char name[20]; //學生姓名 int age; //學生年齡 }student; void main(){ //賦值 strcpy(student.name,"張三"); student.age=23; //控制台輸出 printf("student.name:%s\n",student.name); printf("student.age:%d\n",student.age); }
編譯文件:
原因是在匿名聲明結構體的時候,我就聲明了student變量, 創建匿名結構體的時候,是可以同時聲明變量的,因為它是匿名的, 匿名結構體通常只能用一次。
typedef
typedef, 我感覺還是挺好用的,typedefine的簡寫, 顧名思義就是類型定義,它可以給類型取一個別名.
下面我們可以通過代碼來觀察:
源文件:C:\Users\Zero\Desktop\c\temp\typedef.c
#include<stdio.h> typedef int Integer; //給int類型取個別名Integer typedef double Double; //給double類型取個別名Double void main(){ Integer i=1; //定義整形變量 int j=10; //定義整形變量 Double mark=23.3; //定義雙精度浮點變量 printf("Integer i:%d\n",i); printf("int j:%d\n",j); printf("Double mark:%lf\n",mark); }
即便是取了別名,原來的類型還是可以用的.
編譯文件:
typedef還可以用於結構體上:
源文件:C:\Users\Zero\Desktop\c\temp\typedef.c
顯示聲明:
#include<stdio.h> #include <string.h> //導入strcpy函數的函數庫 //顯示定義學生結構體,別名stu_type typedef struct stu{ char name[20];//學生姓名 int age;//學生年齡 }stu_type; void main(){ stu_type student; //聲明結構體變量student //賦值 strcpy(student.name,"趙七"); student.age=17; //控制台輸出 printf("student.name:%s\n",student.name); printf("student.age:%d\n",student.age); }
結果:
匿名聲明:
源文件:C:\Users\Zero\Desktop\c\temp\typedef3.c
#include <stdio.h> #include <string.h> //導入strcpy函數的函數庫 //匿名定義學生結構體,別名stu_type typedef struct{ char name[20];//學生姓名 int age;//學生年齡 }stu_type; void main(){ stu_type student; //聲明結構體變量student //賦值 strcpy(student.name,"趙九"); student.age=19; //控制台輸出 printf("student.name:%s\n",student.name); printf("student.age:%d\n",student.age); }
結果:
好了,文章到了這裡,也該結束了. 歡迎閱讀我學C的那些年