C語言預處理的相關知識
導語:在C語言編譯的時候,會經歷以下幾個步驟:預處理,編譯,彙編,鏈接,然後生成可執行文件。整個過程是一連串動作完成的。而預處理階段呢,也是在最先執行的一個步驟。相對來説,也是比較重要的一個步驟。那麼C語言預處理的相關知識呢?一起來學習下吧:
概念: 以“#”號開頭的預處理指令如包含#include,宏定義制定#define等,在源程序中這些指令都放在函數之外,而且一般放在源文件的前面 ,所謂預處理其實就是在編譯的第一遍掃描之前的所作的工作,預處理是c語言的一個重要的功能,它由預處理程序單獨完成,當對一個源文件進行編譯時,系統自動引用預處理程序,預處理在 源代碼編譯之前對其進行的一些文本性質的操作,對源程序編譯之前做一些處理,生成擴展的C源程序
預處理階段做了任務:
1:將頭文件中的內容(源文件之外的文件)插入到源文件中
2:進行了宏替換的過程,定義和替換了由#define指令定義的符號
3:刪除掉註釋的過程,註釋是不會帶入到編譯階段
4:條件編譯
預處理指令:
gcc -E bin/helloworld.i src/helloworld.c
預處理生成的是.i的文本文件,這個文本文件是可以直接通過cat命令進行文本文件查看的
宏定義
在C語言中允許用一個標識符來表示一個字符串;稱為宏,在預處理時,對程序的宏進行替換,其中宏定義是由源程序中的#define來完成 ,而宏的替換,主要是由預處理程序完成的
#define PI 3.1415
宏定義的規則:
#表示一條預處理的指令,以#開頭的均是預處理指令
#define是宏定義的指令,標識符是所定義的宏名
宏名一般都是大寫的字母表示,以便和變量名區別
宏定義其實並不是C語言的'語句,所以後面是不用去加;號
宏體可以是常數,表達式,格式化字符串等,為表達式的時候應該用括號闊起來
宏替換不分配內存空間,也不做正確性的檢查
宏的範圍是從定義後到本源文件的結束,但是可以通過#undef來進行提前取消
宏定義分為有參宏定義和無參宏定義:
無參宏定義:
語法:
#define 標識符(宏名)[字符串]
宏體可缺省:
#define YES 1
#define NO 0
#define OUT printf("Hello world")
#define WIDTH 80
#define LENGTH (WIDTH+40)
宏的移除語法
#undef 宏名
功能:刪除前面定義的宏
事例:
#undef PI
#undef OUT
#undef YES
#undef NO
帶參宏定義:
帶參宏定義的語法結構
#define 宏名(形參列表) 字符串(宏體)
帶參數宏定義調用:
宏名(實參表);
C語言中允許宏帶有參數,在宏定義的參數中稱為形式參數,形式參數不分配內存單元,沒有類型定義;
#define S(a,b) a*b;
area = S(3,2);
宏展開 area = 3 * 2;
注意事項:
帶參數宏定義中,宏名和形式參數列表之間不能有空格出現。如
#define MAX (a,b) (a>b)?a:b
此時MAX為無參的宏定義,宏體為(a,b) (a>b)?a:b
#define MAX(a,b) (a>b)?a:b
宏定義中,形參是一個標識符,而宏調用的參數可以是一個表達式
宏體內的形參通常要括號闊起來
#define POWER(x) ((x)*(x))
條件編譯
條件編譯的概念
1:一般情況下,源程序中所有的行都進行編譯,但是有時希望對其中一部分內容滿足一定條件下才進行編譯,也就是對一部分內容指定編譯條件,這就是條件編譯
條件編譯的優點
條件編譯可以指定代碼的一部分是被正常編譯還是被完全忽略
條件編譯有利於提升程序的可移植性,增強程序 的靈活性
條件編譯的相關語法
條件編譯語法一:
#ifdef 標識符(宏名) //或者#if define(標識符)
程序段1
#else
程序段2
#endif
實例代碼:防止多重包含的問題產生
#define HELLO "helloworld"
#ifdef HELLO
#define HI "welcome"
#endif
條件編譯語法二:
#ifndef 標識符(宏名) //或#if !define(標識符)
程序段1
#else
程序段2
#endif
實例:
#ifndef __HELLO_H__
#define __HELLO_H__
void out();
#else
//程序段2
#endif
條件編譯語法三:
#if(常量表達式)
程序段1
#elif(常量表達式2)
程序段2
#else
程序段3
#endif
實例代碼:
#define C1 0
#define C2 0
#define C3 1
#if(C1)
#include "c1.h"
#elif(C2)
#include "c2.h"
#elif(C3)
#include "c3.h"
#else
#include "c.h"
#endif
文件包含
文件包含的概念
文件包含是C預處理程序的另一個重要的功能,被包含的文件名字必須使用雙引號”“(自定義頭文件),或者<>(標準庫文件)括起來,
文件包含的語法:
#include <文件名>
或者
#include "文件名"
文件包含的功能:
一個源文件可以將另外一個源文件的內容包含進來,從而把指定的文件和當前的源文件連成一個源文件
文件包含的處理過程:
在預處理的時候,用被包含文件的內容取代該文件包含指令,再對包含後的文件作一個源文件編譯
文件包含的搜索方式
#include<文件名>
若指定文件目錄(如include)則會從指定目錄中去進行查找,否則就會按照標準的方式進行查找
如:(gcc -o bin/hello -Iinclude src/hello)
標準方式:從系統標準文件所在的目錄中去尋找要包含的文件
linux下:/usr/include或者/usr/lib中主要存放的是標準庫文件
#include "文件名"
先從存放C源文件的目錄中查找,然後從指定的目錄中去查找,最後再從C語言的標準庫文件中去查找
重要:文件的多重包含問題
概念:同一個文件被包含了多次
結果:多重包含可能會出現重複定義的編譯錯誤
解決方式:使用條件編譯(只能是一個源文件中去解決)來防止多重包含,凡是在頭文件前後,用條件編譯去編譯
如標準頭文件的寫法:
#ifndef __HEADER_NAME_H__
#define __HEADER_NAME_H__
#include "headername.h"
//其他的代碼
#endif
如果在多個源文件中進行多重包含的話,使用多重包含的話是解決不了的。需要檢查。
建議注意:
在頭文件中儘量不要去定義一些全局變量,可以在源文件中去定義,用extern去修飾,將變量的作用於釋放帶整個程序
預處理操作符和預定義宏
預處理操作符號:#和##
C語言中有兩個預處理操作符號#和##,它可以在#define中使用
操作符號#通常成為字符串化的操作符號,它把其後的串變成用雙引號包圍的串
如:#define PRINT(FORMAT,VALUE) printf("the value of" #value "is" FORMAT "",VALUE)
PRINT("%d",x+3);
連接操作符號##可以把兩個獨立的字符串鏈接成一個字符串
如:
#define ADD_TO_SUM(sum_number,value) sum##sum_number +=value
ADD_TO_SUM(5,25);
預定義宏和其他指令:
__FILE__ 進行編譯的源文件名稱
__LINE__ 文件當前的行號
__DATE__文件被編譯的日期
__TIME__文件被編譯的時間
__fun__當前所在的函數名稱
其他預處理
#error 自定義輸出的錯誤,是不能鏈接生成可執行文件的
#line 設置當前的文件從哪一行開始計算
#line 100 "hello.c"
#pragma 字節對齊預處理指令
#pragma message("helloworld");----->輸出提示相關信息
以上是個人在學習過程中所做的一些總結性東西,如有不對的地方,希望可以及時指出,歡迎繼續訪問。
-
2017計算機二級C語言精選習題
多做題有助於同學們及時檢測自己的學習情況。希望提供的2017計算機二級C語言精選習題,能夠幫助大家鞏固所學知識,為今後的學習打好基礎!(1)OSI模型的'物理層負責下列哪一種功能?A)格式化報文B)為數據選擇通過網絡的路由C)定義連接到介質的特徵D)提供遠程文件訪...
-
C語言自增(++)和自減(--)
C語言源自KenThompson發明的B語言,那麼大家知道C語言自增(++)和自減(--)是什麼呢?下面一起來看看!一個整數自身加一可以這樣寫:a+=1;它等價於a=a+1;。但是在C語言中還有一種更簡單的寫法,就是a++;或者++a;。這種寫法叫做自加或自增;意思很明確,就是自身加一。相應...
-
2017年計算機二級C語言對C語言的深入探討知識點
引導語:它的應用範圍廣泛,具備很強的數據處理能力。以下是本站小編分享給大家的2017年計算機二級C語言對C語言的深入探討知識點,歡迎閲讀!【考點1】編譯預處理凡以#開頭的這一行,都是編譯預處理命令行,編譯預處理不加分號,不佔運行時間。宏替換僅是簡單的文本替換,如#...
-
c語言—文件的創建與建立
今天要介紹的是有關文件的創建與讀取的語法,事實上,c語言中對於這方面的`已經有相當經典且應用相當廣泛的語法了,但是我今天想講一講關於c++中的相關語法,以下僅供參考!以下是代碼:首先是文件的創建:#include#include#includeusingnamespacestd;intmain(){ofstreamout...