C語言的預編譯,程式設計師必須懂的知識!

2020-12-13 岑寂扶你去學C

由「原始碼」到「可執行文件」的過程包括四個步驟:預編譯、編譯、彙編、連結。所以,首先就應該清楚的首要問題就是:預編譯只是對程序的文本起作用,換句話說就是,預編譯階段僅僅對原始碼的單詞進行變換,而不是對程序中的變量、函數等。

預編譯指令的基本知識不作詳細介紹,只稍作匯總,重點是後面的我能想到的 使用時的注意事項。

1. 基本內容

預編譯指令基本分類如下

類別

指令

預定義符號__FILE__、__LINE__、__DATE__、__TIME__、__STDC__宏#define文件包含#include條件編譯#if、#elif、#else、#ifdef、#ifndef、#endif

還有一些指令,名稱和功能如下表:

指令功能#空指令#undef移除一個空定義#error停止編譯,並生成錯誤信息#line修改__LINE__和__FILE__的值#progma允許編譯器提供額外功能

在定義宏的時候,有兩個運算符:

運算符功能#將宏參數轉換為字符串##將多個符號連接成一個標識符

2. 宏定義

1. 一般在宏定義的結尾不加分號。

我們在使用的時候,要加上分號,像我們平時寫語句一樣。

2. 注意加括號。

在有參數的空定義中,如果含有數值運算,那麼就要在「宏整體」和「宏參數」兩端都要加上括號。

如:#define max(a, b) ((a)+(b));

3. 注意空格。

在有參數的宏定義中,注意「宏名稱」和「參數列表」之間不能有空格。

如:#define max (a, b) ((a)+(b)); 在"max」和」(a, b)」之間不能有空格。

4. 不要使用有副作用的參數區調用宏。

常見的有副作用的參數有:a++,getchar()等。

如:宏定義為#define max (a, b) ((a)+(b)); 那麼使用max(i++, j++)調用該宏,會造成 i 或 j 中的一個值增加2,而不是我們期望的 1。

5. 可以使用編譯器選項 添加宏 和 移除宏。

我使用的是gcc,添加宏的指令是」-D」,移除宏的指令是」-U」。

6. 宏參數替換的時候,不會替換字符串中的字符。

即不會替換雙引號之間的字符,其他的都會被替換,包括單引號之間的。

7. 可以使用#將 宏參數的值 轉化為字符串。

直接使用#,是將宏參數的名稱轉化為字符串。利用下面的技巧(增加一個過渡宏),可以將「宏參數的值」轉化為字符串(當宏參數有值時,這時的宏參數常常也是一個宏)。

[cpp] view plain copy

#include <stdio.h>#include <stdlib.h>#define NUMBER ten /* 宏名稱為NUMBER,宏的值為ten */#define Str(x) #x#define XStr(x) Str(x) /* 增加的一個 過渡宏 */int main(){printf("Str(NUMBER) == %s /n", Str(NUMBER));printf("XStr(NUMBER) == %s /n", XStr(NUMBER));system("pause");return EXIT_SUCCESS;}

輸出結果為:

[cpp] view plain copy

Str(NUMBER) == NUMBERXStr(NUMBER) == ten

8. 使用##運算符來實現標識符連接。

不過,不建議使用操作符##來連接標識符,因為這個容易是程序可讀性大大降低。

3. 文件包含

1. 要將頭文件的定義在保護條件中。

目的是為了防止重複包含頭文件。如果你查看過gcc或者其他編譯器的原始碼,你一定對這個非常熟悉。

例如,你要編寫一個頭文件,myheader.h,那麼你的頭文件的內容形式應該為:(定義一個_MYHEADER宏)

[cpp] view plain copy

#ifndef _MYHEADER#define _MYHEADER 1/* 中間是你的頭文件內容 */#endif /* _MYHEADER */

2. 注意windows系統和Unix系統的路徑符號不同。

可以再#include中指定路徑來包含文件,例如 #include 「../head.h」。但是注意,windows中使用反斜線」/」作為路徑分隔符,而Unix系統使用的是斜線」/」。

3. 可以使用 編譯器選項 來設置搜索路徑。

我使用的gcc,使用的-Idir選項,例如: -I"D:/Dev-Cpp/include"。

4. 條件編譯

1. #ifdef等價於#if defined(),#ifndef等價於#if !defined()。

2. 在#if中可以使用邏輯操作符(&&、||、!)。在#ifdef 中是不可以使用的,這也是#if的優越點。

[cpp] view plain copy

#include <stdio.h>#include <stdlib.h>#define A 1#define B 0int main(){#if defined( A ) && defined( B )printf("test logic operation in #if /n"); /* 如果上面的邏輯判斷成立,那麼將列印出一句話;如果不成立,那麼 就不會列印這句話 */#endifsystem("pause");return EXIT_SUCCESS;}

運行結果:

[cpp] view plain copy

test logic operation in #if

3. sizeof(int)在預編譯階段是不會被求值的。

只要知道「預編譯階段」在真正的「編譯階段」之前,就很容易理解了。預編譯階段只是對組成原始碼中的字符進行作用,從某種意義上來說,它有時甚至不知道它的操作對象是什麼,它只是按照既定的規則執行替換。

sizeof(int),無論是sizeof的解析,還是類型的解析,都是在「編譯階段」才開始的,編譯階段知道它的操作對象是什麼。

下面的代碼是錯誤的

[cpp] view plain copy

#if sizeof(int) == 2printf("precompile sizeof(int)");#endif

5. 額外注意

把一個預處理指令寫成多行的形式,要使用符號」/」,並且在該符號後面應緊跟換行符。而非預處理指令的代碼行不需要使用該符號,直接換行即可。 原因:編譯階段會自動忽略空白符,而預編譯階段不會。

相關焦點

  • 快速上手系列-C語言之預編譯命令、宏定義及條件編譯
    上一篇寫了C語言中變量的存儲類別,提到普通局部變量、普通全局變量和靜態局部變量及靜態全局變量,這裡簡單了解一下C語言的預編譯命令、宏定義和條件編譯。預編譯命令(預編譯處理--->編譯---->彙編--->連接)1、預處理:預處理是C語言的一個重要功能,如文件包含、常量定義都屬於預處理命令,C語言提供的預處理功能主要有以下三種:1)文件包含 #include2)宏定義 #define3)條件編譯 #if #endif4)防止頭文件重複包含2、文件包含處理
  • 終於理解了編譯是怎麼回事!從C語言到機器語言的升華過程!
    在Linux下,使用gcc編譯器: 預編譯hello.c文件: gcc -E -o hello.i hello.c 執行成功後就會生成一個新的hello.i的文件,可以用編輯器(Vim)查看它的內容,這個文件就是經過預編譯後的內容。
  • C語言基礎知識
    pow(x, y)函數C 和 Python 語言的 pow(x, y) 方法都是用於返回 (x 的 y 次方) 的值,C 語言中其原型為:double pow(double x, double y)。下表列出了關於標準浮點類型的存儲大小、值範圍和精度的細節:IO 函數sprintf()函數fopen()函數fwrite()函數預編譯指令
  • C語言陷阱與技巧20節,自定義「編譯時」assert方法,在代碼編譯階段...
    在C語言程序開發中,程式設計師寫代碼時應該考慮的「面面俱到」,這樣才能寫出功能穩定的程序。例如,在實現 open() 函數時,先完成它的功能固然是重要的,但是程式設計師還需要考慮各種「意外」,比如下面這種情況。
  • 深度理解C語言的編譯機制和語言標準,萬物皆可C!
    編程機制  編寫程序時必須遵循確切步驟主要是取決於你的計算機環境。因為 C語言是可以移植的,所以它在許多環境中可用,其中包括 UNIX,Linux,Windows等等 。  不過,讓我們首先來看一看許多環境所共有的一些方面。你完全不必知道運行一個 C 程序後面的事情,但了解一點是一個很好的背景知識。
  • 最全的C語言基礎知識都在這了
    我們用一個簡單的c程序例子,介紹c語言的基本構成、格式、以及良好的書寫風格,加深小夥伴們對C語言的認識。:main() { }這是c語言的基本結構,任何一個程序都必須包含這個結構。4、在{ }裡面每一句話後面都有一個分號(;),在c語言中,我們把以一個分號結尾的一句話叫做一個c語言的語句,分號是語句結束的標誌。
  • Notepad++編譯和運行C語言(GCC)
    我們在學習C語言的時候,實際上只需要編譯器和編輯器就能開搞了。(初學者過早接觸IDE不利於理解程序構建的過程)在看這篇文章的時候,假設你已經知道如何把GCC配置到環境變量,並且會在命令行/終端下使用gcc 編譯C代碼文件 並運行了。
  • 程式設計師術語:什麼是高級語言/低級語言?解釋語言/編譯語言?
    作為一名合格的程式設計師,你必須知道一些計算機軟體編程方面的術語。這次給大家解釋一下下面兩對常見的術語:高級語言/低級語言、解釋語言/編譯語言。相對於高級語言,其優點是執行速度快,但代碼編寫難度較大,可讀性較差。另外,低級語言編寫的程序只能在一種計算機上運行,想要運行在不同的機器上,必須重寫。低級語言是早期的一種計算機程式語言,現在只在很少的特殊場景中使用了。什麼是編譯語言/解釋語言?
  • 函數,從編輯到編譯
    1、預編譯今天的一切看起來都很平凡,至少我是這麼認為的。屏幕外的程式設計師像平常一樣敲著代碼,我們像平常迎接著新函數的到來,像平常一樣嬉笑怒罵,像平常一樣期待著預編譯進程的到來。用專業的話來說,處理 「#include 」預編譯指令,就是將被包含的文件插入到該預編譯指令的位置。這個過程是遞歸進行的,也就是說被包含的文件可能還包含其他文件。
  • iOS編譯過程的原理和應用
    前言一般可以將程式語言分為兩種,編譯語言和直譯式語言。像C++,Objective C都是編譯語言。編譯語言在執行的時候,必須先通過編譯器生成機器碼,機器碼可以直接在CPU上執行,所以執行效率較高。像JavaScript,Python都是直譯式語言。直譯式語言不需要經過編譯的過程,而是在執行的時候通過一個中間的解釋器將代碼解釋為CPU可以執行的代碼。
  • 程式設計師學習C語言編程的4種方法,C語言之父的大作不容錯過!
    不過,有些程式設計師是直接從C語言強勢入門編程的。那麼,如何學習C語言呢?下面w3cschool提供4種入門C語言的方法:0、刷題絕大多數的程式設計師學編程的時候,還是會開啟簡單粗暴的刷題模式。閱代碼百遍不如手過一遍,比如閱讀《C程序設計語言》,最好是將裡面的代碼和習題編譯並運行,甚至還需要調試和改進。有些代碼一眼看過去很簡單,不過當你敲一遍過去,會遇到很多細節的問題。普通程式設計師和優秀程式設計師的區別,往往也在對於細節的觀察和感知上面。
  • 第十七文:編譯基礎知識之cmake第一篇
    聲明:寫這篇文章是因為筆者發現身邊很多小夥伴由於不怎麼需要關心編譯鏈路問題,所以對於編譯的一些基本知識還是不是很了解。
  • 程式設計師應如何理解include
    程式設計師寫的大家都可讀的代碼是不能被CPU直接執行的,CPU可以執行的代碼是二進位機器指令,因此一定有某個過程將程式設計師寫的程序轉換為了機器指令,這就是編譯器。以上大部分同學應該都知道,但是你知道編譯器在將代碼翻譯成機器指令前其實還有一個步驟嗎?這個步驟就是預編譯。
  • Linux下C語言編譯的問題
    連結時缺失了相關目標文件(.o)  測試代碼如下: test.h test.c(調用func.c的函數) func.c main.c(調用test.c的函數)  然後編譯。我們開始編譯main.c  gcc -c main.c  這時,則生成了main.o文件,然後我們再通過如下命令進行連結希望得到可執行程序。
  • C/C+編程筆記:C語言預處理命令是什麼?不要以為你直接寫#就行!
    C語言源文件要經過編譯、連結才能生成可執行程序: 1) 編譯(Compile)會將源文件(.c文件)轉換為目標文件。當對一個源文件進行編譯時,系統將自動調用預處理程序對源程序中的預處理部分作處理,處理完畢自動進入對源程序的編譯。 編譯器會將預處理的結果保存到和源文件同名的.i文件中,例如 main.c 的預處理結果在 main.i 中。和.c一樣,.i也是文本文件,可以用編輯器打開直接查看內容。
  • CSS 預編譯語言 Sass 快速入門教程
    1、CSS 預編譯語言概述CSS 作為一門樣式語言,語法簡單,易於上手,但是由於不具備常規程式語言提供的變量、函數、繼承等機制,因此很容易寫出大量沒有邏輯、難以復用和擴展的代碼,在日常開發使用中,如果沒有完善的編碼規範,編寫的 CSS 代碼會非常冗餘且難以維護。
  • C語言編譯過程中的錯誤分析
    語言的最大特點是:功能強、使用方便靈活。C編譯的程序對語法檢查並不象其它高級語言那麼嚴格,這就給編程人員留下「靈活的餘地」,但還是由於這個靈活給程序的調試帶來了許多不便,尤其對初學C語言的人來說,經常會出一些連自己都不知道錯在哪裡的錯誤。看著有錯的程序,不知該如何改起,本人通過對C的學習,積累了一些C編程時常犯的錯誤,寫給各位學員以供參考。
  • 【C語言】02.第一個C語言程序
    三、連結程序四、運行程序五、總結六、學習建議七、clang指令匯總前言前面已經嘮叨了這麼多理論知識,從這講開始,就要通過接觸代碼來學習C語言的語法。學習任何一門語言,首先要掌握的肯定是語法。學習C語言語法的目的:就是能夠利用C語言編寫程序,然後運行程序跟硬體(計算機、手機等硬體設備)進行交互。由於我們的最終目的是學習iOS開發,學習iOS開發的話必須在Mac系統下,因此我就在Mac系統環境下開發C語言程序,而不是在Windows環境下。
  • C語言入門基礎知識大全
    用一個簡單的c程序例子,介紹c語言的基本構成、格式、以及良好的書寫風格,使小夥伴對c語言有個初步認識。、任何一個c語言程序都必須包括以下格式:main() { }——這是c語言的基本結構,任何一個程序都必須包含這個結構。
  • C語言程式設計師 必讀的5本書