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 宏定义,撤销已经定义的宏名称
#include 使编译程序的另一源文件嵌入到带有#include 的源代码中
#if #else #endif 如果#if 后面的常量表达式为true,则编译它与#endif之间的代码,否则跳过这些代码
#if #elif else #endif 表示如果有定义和如果没有定义,是条件编译的另一种方法
#ifdef #endif 同上
#error 编译程序的时候,遇到#error 就会产生一个编译错误信息,并且停止编译
#pragma 可以设定编译程序完成一系列的动作
#/## 字符串转换和标志符连接
宏定义

宏(Macro),是一种批量处理的称谓,计算机科学里的宏是一种抽象,它根据一系列预定义的规则替换一定的文本模式
宏定义又称为宏代换、宏替换,简称“宏”,宏定义是在编译预处理阶段展开进行替换的。
编译器预定义宏

_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 正确

注意点: 宏定义函数每行必须加上连接符
#define swap(x, y)\
x = x + y;\
y = x - y;\
x = x - y;
或者
#define MALLOC(n, type) \
  ( (type *) malloc((n)* sizeof(type)))
条件编译

条件编译的功能是使得我们可以按照不同的条件去编译不同的程序部分,因而产生不同的目标代码文件,对程序的移植和调试都很有用

  • 形式一
    #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 是条件编译,是根据你是否定义了XXX_XXX这个宏,而使用不同的代码。

#if !defined XXX_XXX
#define XXX_XXX
#endif 是为了避免.h头文件被重复include。

文件包含

文件包含是预处理的一个重要功能,它将多个源文件链接成一个源文件进行编译,结果生成一个目标文件,C语言提供#include命令来实现文件包含的操作,它实际是宏替换的延伸。

  • 格式1
    #include <filename>
    预处理到系统规定的路径去获取这个文件,找到文件后,用文件内容替换该语句。
  • 格式2
    #include “filename”
    标识在当前目录中查找文件名为filename 的文件,如果没有找到,则安装系统指定的路径去搜索其他目录,找到文件后,用文件内容替换该语句。

#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(…) 用于将一个注释记录放入对象文件或者可执行文件中。

  • #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" ] )

例如:
//默认情况下,函数被存放在.text节中
void func1() { // stored in .text
}
//将函数存放在.my_data1节中
#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++; \
}

//...表示所有剩下的参数,__VA_ARGS__被宏定义中的...参数所替换。
//这在c语言的GNU扩展语法里是一个特殊规则:当__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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,133评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,682评论 3 390
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,784评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,508评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,603评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,607评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,604评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,359评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,805评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,121评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,280评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,959评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,588评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,206评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,442评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,193评论 2 367
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,144评论 2 352

推荐阅读更多精彩内容