`
lobin
  • 浏览: 424616 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

C: 第8章 预处理

 
阅读更多

预处理

 

预处理指令

宏定义

#define

 

无参数

#define PI 3.14

 

有参数

可以在一对括号"()"内指定参数。如果有多个参数的话,用逗号","分隔。

#define ADD1(a) a

#define ADD2(a, b) (a + b)

 

ADD1(1)

ADD2(1, 2)

调用时参数个数要对应,有几个参数就必须传几个参数。否则将报错:

error: macro "ADD" requires 2 arguments, but only 1 given

error: ‘ADD’ undeclared (first use in this function)

 

括号"()"内也可以没有参数,表示无参数

#define ADD0() 0

但在调用时也要有括号:

ADD0()

如果没有括号:

ADD0

将会报错:

error: ‘ADD0’ undeclared (first use in this function)

这跟上面的无参数的宏不一样,其实是两个不一样的宏。

 

和函数一样,宏定义也不允许重载

 

#define ADD(a, b) (a + b)

#define ADD(a, b, c) (a + b + c)

这样会提示警告:

warning: "ADD" redefined

 

ADD(1, 2)

ADD(1, 2, 3)

如果使用的话会报错:

error: macro "ADD" requires 3 arguments, but only 2 given

error: ‘ADD’ undeclared (first use in this function)

 

上面其实后面的重复宏定义已经将前面的宏定义覆盖了。使用的时候按照最后的宏定义使用就不会报错了:

//ADD(1, 2);

ADD(1, 2, 3);

 

#undef

和#define对应,#define用于定义宏,#undef用于取消宏定义。

 

 

 

__FILE__

 

__LINE__

 

__FUNCTION__

 

__func__

 

__DATE__

 

__TIME__

 

__VA_ARGS

 

__VA_ARGS__

 

操作符

宏定义中有两个比较特殊的操作符。

#和##用于对宏参数字符串化和连接操作。

 

#

 

#define __LOG0__(F, L, FORMAT)     \
do {                                       \
  printf((F ":" "(" #L ")" " " FORMAT "\n")); \
} while (0)

 

__LOG0__(__FILE__, 50, "hello, c");

string_test_3.c:(50) hello, c

 

__LOG0__(__FILE__, __LINE__, "hello, c");

string_test_3.c:(__LINE__) hello, c

 

 

#define __FORMAT__(F, L, FORMAT) (F ":" "(" #L ")" " " FORMAT "\n")

#define LOG0(F, L, FORMAT)     \
do {                                       \
  printf(__FORMAT__(F, L, FORMAT)); \
} while (0)

 

LOG0(__FILE__, __LINE__, "hello, c");

string_test_3.c:(53) hello, c

 

##

 

#define ____R____0_1(CB, LEAD, ARGS...)
#define ____R____1_1(CB, LEAD, ARGS...) CB(LEAD) ____R____0_1(CB, ARGS)
#define ____R____2_1(CB, LEAD, ARGS...) CB(LEAD) ____R____1_1(CB, ARGS)
#define ____R____3_1(CB, LEAD, ARGS...) CB(LEAD) ____R____2_1(CB, ARGS)
#define ____R____4_1(CB, LEAD, ARGS...) CB(LEAD) ____R____3_1(CB, ARGS)
#define ____R____5_1(CB, LEAD, ARGS...) CB(LEAD) ____R____4_1(CB, ARGS)
#define ____R____(CB, N, LEAD, ARGS...) ____R____##N##_1(CB, LEAD, ARGS)


#define ____R_WITH_CB____(CB, N, ARGS...) ____R____(CB, N, ARGS)

 

 

#define FN(ARG) ARG

int main(int argc, char **argv)
{
  printf(____R_WITH_CB____(FN, 0) "\n");
  printf(____R_WITH_CB____(FN, 1, "A") "\n");
  printf(____R_WITH_CB____(FN, 2, "A", "B") "\n");
  printf(____R_WITH_CB____(FN, 3, "A", "B", "C") "\n");
  printf(____R_WITH_CB____(FN, 4, "A", "B", "C", "D") "\n");
  printf(____R_WITH_CB____(FN, 5, "A", "B", "C", "D", "E") "\n");
  return 0;
}

 

 

#define FN2(FMT) printf(FMT "\n");

____R_WITH_CB____(FN2, 1, "A");
____R_WITH_CB____(FN2, 2, "A", "B");
____R_WITH_CB____(FN2, 3, "A", "B", "C");
____R_WITH_CB____(FN2, 4, "A", "B", "C", "D");
____R_WITH_CB____(FN2, 5, "A", "B", "C", "D", "E");

 

#line

#line预处理指令将影响__FILE__, __LINE__的值。

 

#define __FORMAT__(F, L, FORMAT) (F ":" "(" #L ")" " " FORMAT "\n")

#define LOG0(F, L, FORMAT)     \
do {                                       \
  printf(__FORMAT__(F, L, FORMAT)); \
} while (0)

 

  LOG0(__FILE__, __LINE__, "hello, c");

#line 99 __FILE__
  LOG0(__FILE__, __LINE__, "hello, c");
  LOG0(__FILE__, __LINE__, "hello, c");
  LOG0(__FILE__, __LINE__, "hello, c");
  LOG0(__FILE__, __LINE__, "hello, c");

#line 67 __FILE__
  LOG0(__FILE__, __LINE__, "hello, c");

string_test_3.c:(58) hello, c
string_test_3.c:(99) hello, c
string_test_3.c:(100) hello, c
string_test_3.c:(101) hello, c
string_test_3.c:(102) hello, c
string_test_3.c:(67) hello, c

 

 

实现函数回调的宏定义

#define FX(CB, FMT) CB(FMT)

#define FN(ARG) printf(ARG)
FX(FN, "222\n");

222

也可以去回调函数

#define FX(CB, FMT) CB(FMT)

#define FN(ARG) printf(ARG)

void fn2(char* arg)
{
  printf(arg);
}

 

FX(fn2, "333\n");

333

 

头文件包含

#include

头文件包含有两种形式

#include<stdio.h>

#include"stdio.h" 

这两种形式在搜索头文件路径顺序是不同的。尖括号不是操作符,仅仅只是一个分界符。双引号也是一样。尖括号和双引号包含的文件名不是字符串,就是一个字符串字面量(string literal)。

 

搜索路径

编译器在实现的时候,对于include的头文件,会按照规定的搜索路径查找头文件。

 

可以参考gcc的搜索路径

写道
https://gcc.gnu.org/onlinedocs/cpp/Search-Path.html#Search-Path

可以通过以下命令查看头文件搜索路径

$ cpp -v /dev/null -o /dev/null

#include "..." search starts here:

#include <...> search starts here:

 /usr/local/include

 /Users/admin/Downloads/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/8.0.0/include

 /Users/admin/Downloads/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include

 /usr/include

 /System/Library/Frameworks (framework directory)

 /Library/Frameworks (framework directory)

End of search list.

 

也可以通过以下方式查看头文件搜索路径

$ `gcc -print-prog-name=cc1` -v

忽略不存在的目录“/usr/lib/gcc/i686-pc-cygwin/4.5.3/../../../../i686-pc-cygwin/include”

#include "..." 搜索从这里开始:

#include <...> 搜索从这里开始:

 /usr/local/include

 /usr/lib/gcc/i686-pc-cygwin/4.5.3/include

 /usr/lib/gcc/i686-pc-cygwin/4.5.3/include-fixed

 /usr/include

搜索列表结束。

 

如果是C++的话

$ `gcc -print-prog-name=cc1plus` -v

忽略不存在的目录“/usr/lib/gcc/i686-pc-cygwin/4.5.3/../../../../i686-pc-cygwin/include”

#include "..." 搜索从这里开始:

#include <...> 搜索从这里开始:

 /usr/lib/gcc/i686-pc-cygwin/4.5.3/include/c++

 /usr/lib/gcc/i686-pc-cygwin/4.5.3/include/c++/i686-pc-cygwin

 /usr/lib/gcc/i686-pc-cygwin/4.5.3/include/c++/backward

 /usr/local/include

 /usr/lib/gcc/i686-pc-cygwin/4.5.3/include

 /usr/lib/gcc/i686-pc-cygwin/4.5.3/include-fixed

 /usr/include

搜索列表结束。

 

 

预处理条件判断

这也是一种包含,表示条件包含。通过此指令可以将符合条件的内容包含到源程序中。也通常通过此指令将符合条件的代码直接inline到函数中。

 

#if

 

#ifdef

 

#elif

 

#else

 

#endif

 

defined

在#if,#elif中可以通过defined判断指定的宏是否定义。等同于#ifdef。

 

错误告警

#warning

 

#error

 

 

#pragma

 

#pragma message string

 

#pragma GCC warning message

 

#pragma GCC error message

 

 

 

 

 

 

分享到:
评论

相关推荐

    C语言程序设计教学课件:第8章 编译预处理.ppt

    在C语言程序设计中,编译预处理是一个重要的步骤,它在正式编译源代码之前进行,主要包括宏定义、文件包含和条件编译等操作。本章主要关注的是宏定义,分为无参宏定义和带参宏定义。 无参宏定义是通过`#define`...

    C语言第一章概述

    第一章:C语言程序设计概述 2课时 第二章:基本数据类型与表达式 4课时 ...第八章:指针 8课时 第九章:结构体数据类型与链表 6课时 第十章:共用体与枚举类型 4课时 第十一章:文件

    c语言第8章编译预处理与位运算习题集答案解析.doc

    C语言第8章编译预处理与位运算习题集答案解析 本文档提供了C语言第8章编译预处理与位运算习题集的答案解析,涵盖了宏定义、文件包含、条件编译、位运算等知识点。 一、选择题 1. 在宏定义#define A 3.897678中,...

    二级C语言 第八章 编译预处理.doc

    在C语言中,编译预处理是一个重要的环节,它在正式编译程序之前对源代码进行处理,主要包括宏定义、文件包含和条件编译等操作。编译预处理指令以"#"号开头,用于扩展C语言的功能,增强程序的可读性、可维护性和可...

    二级C语言 第八章 编译预处理.docx

    在C语言中,编译预处理是程序编译过程中的第一步,它主要负责处理源代码中的特定指令,这些指令在实际编译之前被执行。本章主要涵盖了三个关键知识点:宏定义及其调用、文件包含处理以及条件编译指令。 1. **宏定义...

    C语言程序设计教程第8章预处理.ppt

    《C语言程序设计教程第8章预处理》深入解析 C语言编程中,预处理是程序编译过程的重要环节,它在正式的编译和链接之前先对源代码进行处理,主要包括宏定义、文件包含和条件编译等功能,极大地提高了程序的可读性...

    C语言课件:第一章 C语言概述.ppt

    8. 语法检查:尽管C语言的语法检查较为宽松,如不检查数组下标越界,这可能导致一些潜在的错误,但也给予了程序员更高的灵活性。 C语言程序通常由预处理、编译、链接三个阶段组成。例如: ```c #include "stdio.h...

    kj-第8章预处理命令ppt课件(全).ppt

    第 8 章 预处理命令是 C 语言编程中的一个重要概念,它涉及到程序在实际编译之前的一些预备处理工作。预处理命令主要由宏定义、文件包含和条件编译三部分组成,这些功能使得程序员能够更灵活地编写和管理代码。 1. ...

    C语言全套资料 C语言程序设计 C语言算法 C语言课件

    C语言全套资料 C语言程序设计 C语言算法 C语言课件 C语言顺序程序设计 C语言数组 C语言循环控制 C语言预处理命令 C语言文件...第八章 函数 第九章编译预处理命令 第十章 指针 第十一章 结构体与共用体 第十三章 文件

    数据库系统概论:第八章SQL数据库编程

    ### 数据库系统概论:第八章SQL数据库编程 #### 8.1 嵌入式SQL 嵌入式SQL是一种将SQL语句嵌入到高级程序设计语言中的技术,允许开发人员结合SQL的强大数据处理能力与宿主语言的流程控制功能。这种方式克服了SQL...

    kj-第8章预处理命令.ppt

    C语言程序设计(第三版)高禹 电子课件

    C程序设计:第1章 C语言概述.ppt

    C程序的格式和结构通常包括预处理指令、声明、函数定义和调用等部分。一个典型的C程序通常包含头文件、变量声明、函数定义和主函数。程序的运行过程一般分为编辑、编译、链接和执行四个步骤。 学习C语言,需要注重...

    第8章 编译预处理.ppt

    第8章 编译预处理主要探讨的是在C语言编程中,如何在编译之前对源代码进行处理,以优化和准备源程序的编译过程。这个过程涉及到宏定义、文件包含和条件编译三个主要方面。 8.1 宏定义与符号常量 宏定义是C语言中一...

    数据库系统概论:第8章 数据库编程.ppt

    《数据库系统概论:第8章 数据库编程》这一章主要介绍了在数据库系统中如何进行编程,特别是关于SQL的使用方式。SQL(Structured Query Language)是用于管理关系数据库的标准语言,它分为交互式和嵌入式两种使用...

    c语言配套教材电子教案

    第1章 C语言概述 ...第8章 函数 第9章 预处理命令 第10章 指针 第11章 结构体与共用体 第12章 位运算 第13章 文件 第14章 C++对C的扩充 第15章 C++的面向对象基础 第16章 常见错误和程序调试

    c语言教程+ 100例经典c程序

    第一章: C语言概论 第二章: 数据类型、运算符、表达式 第三章: C语言程序设计初步 第四章: 数组 第五章:函数 第六章:指针 ...第八章:枚举,位运算 第九章: 预处理 第十章: 文件 +100例经典c程序

    GPS测量原理及应用:第八章 GPS测量的设计与实施.ppt

    数据预处理包括去除噪声、异常值检测和基线解算,最后进行质量检核和技术总结,以确保测量结果的准确性和有效性。 总结来说,GPS测量的设计与实施是一个系统的过程,需要综合考虑技术规范、精度要求、基准转换和...

    c语言程序设计教程 ppt

    内容: 第一章:c语言程序设计预备知识 第二章:c语言程序设计基础 第三章:基本数据类型、运算符与表达式 ...第八章:函数 第九章:指针 第十章:预处理命令 第十一章:复杂数据类型 第十二章:文件 实验

    C语言程序设计第二章习题参考答案

    在C语言程序设计的学习过程中,第二章通常会涵盖基础语法和基本编程概念。这份"第二章习题参考答案"提供了对这些概念的实践应用解析,旨在帮助学习者巩固理论知识,提升编程技能。以下是根据标题、描述和标签提取的...

    C语言基础入门视频.txt

    本文是txt文本里面有网盘永久链接视频,C语言基础,包括:002第二章 数据类型,运算符和表达式01,007第三章 顺序...函数01,042第八章 指针02(新版),052第九章 预处理03(新版),065第十一章 位运算02(新版),一共11章

Global site tag (gtag.js) - Google Analytics