C 語言學習(2) ---- C/C++ 語言中的預處理

C語言預處理功能概要

功能 說明
宏定義 #define,#undef
文件包含 #include
條件編譯 #ifdef,#ifndef,#if,#elif,#if definedxxx,#else,#endif
編譯信息和警告 #pragma message("message"),#pragma warning,#error
文件名和行信息 #line
標識符連接 x##8,將變量轉換為字符串
ANSI_C定義的C語言預處理指令

預處理名稱以及對應的含義

功能 說明
#define,#undef 宏定義,撤銷已經(jīng)定義的宏名稱
#include 使編譯程序的另一源文件嵌入到帶有#include 的源代碼中
#if #else #endif 如果#if 后面的常量表達式為true,則編譯它與#endif之間的代碼,否則跳過這些代碼
#if #elif else #endif 表示如果有定義和如果沒有定義,是條件編譯的另一種方法
#ifdef #endif 同上
#error 編譯程序的時候,遇到#error 就會產(chǎn)生一個編譯錯誤信息,并且停止編譯
#pragma 可以設定編譯程序完成一系列的動作
#/## 字符串轉換和標志符連接
宏定義

宏(Macro),是一種批量處理的稱謂,計算機科學里的宏是一種抽象,它根據(jù)一系列預定義的規(guī)則替換一定的文本模式
宏定義又稱為宏代換、宏替換,簡稱“宏”,宏定義是在編譯預處理階段展開進行替換的。
編譯器預定義宏

_LINE_  編譯文件的行號字符串
_DATE_  編譯時刻日期字符串
_FILE_   編譯文件名稱
_TIME_ 編譯文件時間字符串
_STDC_ 判斷文件是不是定義成標準C
注意點:宏定義字符串不需要雙引號

#define PATH "C:\English\demo" 錯誤
#define PATH C:\English\demo 正確

注意點:宏定義中要添加括號

NA

注意點:. 宏定義常量的時候注意后綴

#defien SEC_A_YEAR (60*60*24*365) 錯誤
#defien SEC_A_YEAR (60*60*24*365)UL 正確

注意點: 宏定義函數(shù)每行必須加上連接符
#define swap(x, y)\
x = x + y;\
y = x - y;\
x = x - y;
或者
#define MALLOC(n, type) \
 ?。?(type *) malloc((n)* sizeof(type)))
條件編譯

條件編譯的功能是使得我們可以按照不同的條件去編譯不同的程序部分,因而產(chǎn)生不同的目標代碼文件,對程序的移植和調(diào)試都很有用

  • 形式一
    #ifdef 標識符
    #endif

  • 形式二
    #ifdef 標識符
    #else
    #endif

  • 形式三
    #ifndef 標識符
    #else
    #endif

  • 形式四
    #if 常量表達式
    程序段1
    #else
    程序段
    #endif
    如果常量表達式的值為真,則進行程序段1的編譯,否則進行程序段2 的編譯

實例:

    #if (demo_a == true)
    //#if (demo_a)
        MI_PRINT("demoa == true \n");
    #else
        MI_PRINT("demoa != true \n");
    #endif
    #if (demo_c == 1)
        MI_PRINT("demo_C = 1 \n");
    #elif (demo_c == 2)
        MI_PRINT("demo_C = 2 \n");
    #elif (demo_c == 3)
        MI_PRINT("demo_C = 3\n");
        #error this is my error
    #elif (demo_c == 4)
        MI_PRINT("demo_C = 4\n");
        #error this is my error
    #endif
  • 形式五
    #if defined XXX_XXX
    #endif 是條件編譯,是根據(jù)你是否定義了XXX_XXX這個宏,而使用不同的代碼。

#if !defined XXX_XXX
#define XXX_XXX
#endif 是為了避免.h頭文件被重復include。

文件包含

文件包含是預處理的一個重要功能,它將多個源文件鏈接成一個源文件進行編譯,結果生成一個目標文件,C語言提供#include命令來實現(xiàn)文件包含的操作,它實際是宏替換的延伸。

  • 格式1
    #include <filename>
    預處理到系統(tǒng)規(guī)定的路徑去獲取這個文件,找到文件后,用文件內(nèi)容替換該語句。
  • 格式2
    #include “filename”
    標識在當前目錄中查找文件名為filename 的文件,如果沒有找到,則安裝系統(tǒng)指定的路徑去搜索其他目錄,找到文件后,用文件內(nèi)容替換該語句。

#include也是支持相對路徑的,格式如下
. 代表當前路徑
.. 代表上一級目錄

預處理
  • #error message
    編譯程序的時候,只要遇到#error 就會生成一個編譯錯誤提示消息,并且停止編譯
    #error 編譯器錯誤 (不需要加引號)
  • #pragma 消息文本
    比如:
    #pragma message("now we run into this \n")
    在編譯就會在編譯log 中打印上面的文本
    這個命令可以幫助我們判斷編譯的流程
    #ifndef BIONIC
    #pragma message("not define bionic \n")
    #endif

  • #pragma once
    頭文件中加入這條指令就可以保證頭文件被編譯一次,防止重復包含。

#pragma resource
#pragma resource “*.dfm” 表示把*.dfm 的資源都加入工程。

  • #pragma comment
    #pragma comment(…) 用于將一個注釋記錄放入對象文件或者可執(zhí)行文件中。

  • #pragma comment(lib, “user32.lib”)
    上面的指令用于將 user32.lib 放入工程中。

  • #pragma warning
    常用:
    #pragma warning(disable:4507 34) 不顯示4507 和34 號警告
    #pragma warning(once:4385) 4385號警告信息僅僅報告一次
    #pragma warning(error:164) 將164 號警告作為一個錯誤

  • #pragma code_seg
    #pragma code_seg( [ [ { push | pop}, ] [ identifier, ] ] [ "segment-name" [, "segment-class" ] )

例如:
//默認情況下,函數(shù)被存放在.text節(jié)中
void func1() { // stored in .text
}
//將函數(shù)存放在.my_data1節(jié)中
#pragma code_seg(".my_data1")
void func2() { // stored in my_data1
}

  • #與##
    # 可以將語言符號轉換為字符串
    #define STRING(x) #x STRING(1+1) 相當于變成了 “1+1” 字符串

## 用于將前后的字符串連接起來
比如定義:
#define XNAME(n) x##n
XNAME(8) 等同于 x8

示例代碼

//標記前使用“#”特殊符號將其轉換為字符串的標記
#define GET_STRING(n) #n
//## 用于將兩個標志符用字符串的方式連接
#define CONNECT(a, b) a##b
//多行的宏要用連接符連接 最后一行不需要使用
#define MACRO(n, limit) while (n < limit) \
{ \
    printf("minger "); \
    n++; \
}

//...表示所有剩下的參數(shù),__VA_ARGS__被宏定義中的...參數(shù)所替換。
//這在c語言的GNU擴展語法里是一個特殊規(guī)則:當__VA_ARGS__為空時,會消除前面這個逗號
#ifndef debugPrintf
#define debugPrintf(...) printf("DEBUG: " __VA_ARGS__);
#else
#define debugPrintf(...)
#endif

cdefineDemo::cdefineDemo() {
    auto printDemo = [](string& s)->void {
        cout << " printDemo " << s << endl;
    };


    cout << "cdefineDemo start..." << endl;
    cout << "GET_STRING:" << GET_STRING(this is my string) << endl;;
    cout << "COONECT A B: " << CONNECT(12,34) << endl;

    string p = "stringA";
    CONNECT(print, Demo)(p); // using connect as function name 

    debugPrintf("demo printf %s",p.c_str());
}
Review History
日期 說明
2022/10/31 修改部分格式
NA NA
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容