摘要:傳送門(mén)樓下大爺看完直呼簡(jiǎn)單語(yǔ)言預(yù)處理上一命令行編譯什么是命令行編譯在編譯的時(shí)候通過(guò)命令行的方式對(duì)其進(jìn)行相關(guān)的定義,叫做命令行編譯。替換方式為,預(yù)處理器先刪除這條指令,并用包含文件的內(nèi)容替換。
本文為C語(yǔ)言預(yù)處理的下篇,將繼續(xù)講解C語(yǔ)言預(yù)處理的基礎(chǔ)知識(shí)。
? 傳送門(mén):樓下大爺看完直呼簡(jiǎn)單!C語(yǔ)言預(yù)處理(上)
? 什么是命令行編譯?
? 在編譯的時(shí)候通過(guò)命令行的方式對(duì)其進(jìn)行相關(guān)的定義,叫做命令行編譯。
? 介紹:許多C的編譯器提供的一種能力,允許在命令行中定義符號(hào)。用于啟動(dòng)編譯過(guò)程。當(dāng)我們根據(jù)同一個(gè)源文件要編譯出不同的一個(gè)程序的不同版本的時(shí),可以用到這種特性,增加靈活性。
? 例子:假如某個(gè)程序中聲明了一個(gè)某個(gè)長(zhǎng)度的數(shù)組,假如機(jī)器甲內(nèi)存有限,我們需要一個(gè)很小的數(shù)據(jù),但是機(jī)器丙的內(nèi)存較大,我們需要一個(gè)大點(diǎn)的數(shù)組。
#include int main() { int arr[ARR_SIZE]; int i = 0; for (i = 0; i < ARR_SIZE; i++) { arr[i] = i; } for (i = 0; i < ARR_SIZE; i++) { printf("%d ", arr[i]); } printf("/n"); return 0;}
? gcc 環(huán)境下測(cè)試:(VS 里面不太好演示)
gcc test.c -D ARR_SIZE=5
ls
a.out? test.c
./a.out
0 1 2 3 4 5
gcc test.c -D ARR_SIZE=20
./a.out
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
? 在編譯一個(gè)程序時(shí),通過(guò)條件編譯指令將一條語(yǔ)句(一組語(yǔ)句)編譯或者放棄是很方便的。
? 調(diào)試用的代碼刪除了可惜,保留了又礙事。我們就可以使用條件編譯來(lái)選擇性地編譯:
#include #define __DEBUG__ // 就像一個(gè)開(kāi)關(guān)一樣int main(void){ int arr[10] = {0}; int i = 0; for (i = 0; i < 10; i++) { arr[i] = i; #ifdef __DEBUG__ // 因?yàn)開(kāi)_DEBUG__被定義了,所以為真 printf("%d ", arr[i]); // 就打印數(shù)組 #endif // 包尾 } return 0;}
? 運(yùn)行結(jié)果:1 2 3 4 5 6 7 8 9 10
?? 如果不想用了,就把 #define __DEBUG__ 注釋掉:
#include // #define __DEBUG__ // 關(guān)int main(void){ int arr[10] = {0}; int i = 0; for (i = 0; i < 10; i++) { arr[i] = i; #ifdef __DEBUG__ // 此時(shí)ifdef為假 printf("%d ", arr[i]); #endif } return 0;}
? (代碼成功運(yùn)行)
? 介紹:如果常量表達(dá)式為真,參加編譯。反之如果為假,則不參加編譯。
? 代碼演示:常量表達(dá)式為真
#include int main(void) {#if 1 printf("Hello,World!/n");#endif return 0;}
?? 運(yùn)行結(jié)果:Hello,World!
? 代碼演示:常量表達(dá)式為假
#include int main(void) {#if 0 printf("Hello,World!/n");#endif return 0;}
? (代碼成功運(yùn)行)
? 當(dāng)然也可以用宏替換,可以表示地更清楚:
#include #define PRINT 1#define DONT_PINRT 0int main(void) {#if PRINT printf("Hello,World!/n");#endif return 0;}
? 介紹:多分支的條件編譯,直到常量表達(dá)式為真時(shí)才執(zhí)行。
? 代碼演示:
#include int main(void) {#if 1 == 2 // 假 printf("rose/n");#elif 2 == 2 // 真 printf("you jump/n");#else printf("i jump/n")#endif return 0;}
? 代碼運(yùn)行結(jié)果:you jump
? 定義:ifdef 和 if defined() ,ifndef 和 if !defined() 效果是一樣的,用來(lái)判斷是否被定義。
? 代碼演示:
#include #define TEST 0// #define TEST2 // 不定義int main(void) {/* 如果TEST定義了,下面參與編譯 */// 1#ifdef TEST printf("1/n");#endif// 2#if defined(TEST) printf("2/n");#endif/* 如果TEST2不定義,下面參與編譯 */// 1#ifndef TEST2 printf("3/n");#endif// 2#if !defined(TEST2) printf("4/n");#endif return 0;}
? 和 if 語(yǔ)句一樣,是可以嵌套的:
#if defined(OS_UNIX) #ifdef OPTION1 unix_version_option1(); #endif #ifdef OPTION2 unix_version_option2(); #endif#elif defined(OS_MSDOS) #ifdef OPTION2 msdos_version_option2(); #endif#endif
我們已經(jīng)知道,#include 指令可以使另外一個(gè)文件被編譯。就像它實(shí)際出現(xiàn)于 #include 指令的地方一樣。替換方式為,預(yù)處理器先刪除這條指令,并用包含文件的內(nèi)容替換。這樣一個(gè)源文件被包含10次,那就實(shí)際被編譯10次。
?? < > 和 " " 包含頭文件的本質(zhì)區(qū)別:查找的策略的區(qū)別
① " " 的查找策略:先在源文件所在的目錄下查找。如果該頭文件未找到,則在庫(kù)函數(shù)的頭文件目錄下查找。(如果仍然找不到,就提示編譯錯(cuò)誤)
Linux環(huán)境 標(biāo)準(zhǔn)頭文件的路徑:
/usr/include
VS環(huán)境 標(biāo)準(zhǔn)頭文件的路徑:
C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/include
② < > 的查找策略:直接去標(biāo)準(zhǔn)路徑下去查找。(如果仍然找不到,就提示編譯錯(cuò)誤)
? 既然如此,那么對(duì)于庫(kù)文件是否也可以使用 " " 包含?
? 當(dāng)然可以。但是這樣做查找的效率就低些,當(dāng)然這樣也不容易區(qū)分是庫(kù)文件還是本地文件了。為了效率不建議這么做。
? 代碼演示:
①? add.h
int Add(int x, int y);
②? add.c
int Add(int x, int y) { return x + y;}
③? test.c
#include #include "add.h"int main(void) { int a = 10; int b = 20; int ret = Add(a, b); printf("%d/n", ret); return 0;}
? 運(yùn)行結(jié)果:30
?? 頭文件重復(fù)引入的情況:
comm.h 和 comm.c 是公共模塊。
test1.h 和 test1.c 使用了公共模塊。
test2.h 和 test2.c 使用了公共模塊。
test.h 和 test.c 使用了 test1 模塊和 test2 模塊。
這樣最終程序中就會(huì)出現(xiàn)兩份 comm.h 的內(nèi)容,這樣就造成了文件內(nèi)容的重復(fù)。
? 那么如何避免頭文件的重復(fù)引入呢?
? 使用條件編譯指令,每個(gè)頭文件的開(kāi)頭寫(xiě):
#ifndef __TEST_H__#define __TEST_H__// 頭文件的內(nèi)容#endif
? 如果嫌麻煩,還有一種非常簡(jiǎn)單的方法:
#pragma once // 讓頭文件即使被包含多次,也只包含一份
?
? 筆試題:選自《高質(zhì)量C/C++編程指南》
① 頭文件中的 ifnde / define / endif 是干什么用的?
答:防止頭文件被重復(fù)多次包含。
② #include <filename.h> 和 #include "filename.h" 有什么區(qū)別?
答:尖括號(hào)是包含庫(kù)里面的頭文件的,雙引號(hào)是包含自定義頭文件的。它們?cè)诓檎也呗陨喜煌?,尖括?hào)直接去庫(kù)目錄下查找。而警號(hào)雙引號(hào)是現(xiàn)去自定義的代碼路徑下查找,如果找不到頭文件,則在庫(kù)函數(shù)的頭文件目錄下查找。
?
陳正沖. 《C語(yǔ)言深度解剖》[M]. 第三版. 北京航空航天大學(xué)出版社, 2019.
比特科技. C語(yǔ)言進(jìn)階[EB/OL]. 2021[2021.8.31]. .
林銳博士. 《高質(zhì)量C/C++編程指南》[M]. 1.0. 電子工業(yè), 2001.7.24.
本章完。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/118779.html
摘要:快杰云主機(jī)搭建??旖茉浦鳈C(jī),搭載選用第二代處理器,主頻,領(lǐng)先的制程工藝帶來(lái)顯著的性能提升,使之打破總體性?xún)r(jià)比世界記錄。因此,糖豆與神策數(shù)據(jù)此次最終共同選擇了快杰服務(wù)器。在涼風(fēng)習(xí)習(xí)的夜晚里,璀璨的燈火映照下,隨處都能碰到翩翩起舞的人群,這就是廣場(chǎng)舞,在這嘹亮、節(jié)奏鮮明的歌聲里有一款大媽們熱愛(ài)的APP—-?糖豆APP。 ?一、挑戰(zhàn) 在發(fā)展之初,多家企業(yè)看好廣場(chǎng)舞這個(gè)賽道,而糖豆創(chuàng)業(yè)初...
摘要:如果經(jīng)過(guò)一系列輸入,最終如果能達(dá)到狀態(tài),則輸入內(nèi)容一定滿(mǎn)足正則表達(dá)式。正則表達(dá)式可以轉(zhuǎn)換為,已經(jīng)有成熟的算法實(shí)現(xiàn)這一轉(zhuǎn)換。不過(guò)有時(shí)候轉(zhuǎn)換為可能導(dǎo)致?tīng)顟B(tài)空間的指數(shù)增長(zhǎng),因此直接用識(shí)別正則表達(dá)式。 原文地址 先來(lái)看一個(gè)讓人震撼的小故事,故事來(lái)自知乎問(wèn)題PC用戶(hù)的哪些行為讓你當(dāng)時(shí)就震驚了? 同學(xué)在一個(gè)化妝品公司上班,旁邊一個(gè)大媽?zhuān)ㄋ氖鄽q)發(fā)給他一個(gè)exl表,讓他在里面幫忙找一個(gè)經(jīng)銷(xiāo)商的資料...
摘要:傳輸協(xié)議問(wèn)題我們先解決第一個(gè),傳輸協(xié)議的問(wèn)題。信封里面的信分抬頭和正文板栗燜雞協(xié)議我們學(xué)過(guò),這個(gè)請(qǐng)求使用方法,發(fā)送一個(gè)格式為的正文給,從而下一個(gè)單,這個(gè)訂單封裝在的信封里面,并且表明這是一筆交易,而且訂單的詳情都已經(jīng)寫(xiě)明了。 【前五篇】系列文章傳送門(mén): 網(wǎng)絡(luò)協(xié)議 15 - P2P 協(xié)議:小種子大學(xué)問(wèn) 網(wǎng)絡(luò)協(xié)議 16 - DNS 協(xié)議:網(wǎng)絡(luò)世界的地址簿 網(wǎng)絡(luò)協(xié)議 17 - HTTPDN...
閱讀 2593·2021-09-22 15:15
閱讀 725·2021-09-02 15:11
閱讀 1908·2021-08-30 09:48
閱讀 1964·2019-08-30 15:56
閱讀 1605·2019-08-30 15:52
閱讀 2146·2019-08-30 15:44
閱讀 507·2019-08-29 16:29
閱讀 1606·2019-08-29 11:06