在C语言中使用宏,我们经常这么做,但是为什么使用宏,他可以做什么,我们或许只是一知半解,下面简单介绍如何在C语言中使用宏预处理器。

#define语句

对于define语句,我们已经非常熟悉,一个宏定义语句,主要用途是定义符号常量,如:

#define PI 3.14159

定义了圆周率PI 为3.14159,在以后用到3.14159的地方直接用PI代替即可,也方便我们编写代码,更大的好处是,如果我不想将圆周率定为3.14159而要求更高精度,如3.14159265,则只需将上面的宏定义改为:

#define PI 3.1415926

即可,无需到程序中用到这个值的地方逐一修改。

下面介绍#define的高级应用

A、 带有参数的宏定义语句

我们也可以定义接受参数的符号,如AQUARE:

#define SQUARE(x) x*x

在以后用到SQUARE(a) 是,将会自动用a*a替换,

如SQUARE(3)将被替换成3*3,这个函数的好处是不论x是什么类型,都可进行同样的处理,double,int类型都可处理,但存在一个问题,如

y=SQUARE(a+1)则将被替换成a+1*a+1

这不是我们想要的结果,所以最好用下面的方法定义

#define SQUARE(x)  (x)*(x)

类似可以定义如下函数:

#define  MAX(a,b)  ((a)>(b))?(a):(b))

B、接受可变参数个数的宏

宏定义同样可以接受可变参数个数的参数列表,为了向预处理器表明我们的宏接受可变参数,可以在参数列表后面跟上三个点(...),在随后的宏定义表达式中,我们使用特殊符号__VA_ARGS__来代表具体参数(注意,前后是双下划线),例如我们定义:

#define debugPrintf(...)  printf("DEBUG: "__VA_ARGS__)

则可用下面方式使用该宏

debugPrintf("Hello world\n");

或者

debugPrintf("i= %d, j=%d \n",i,j);

输出分别为(加入i=100,j=200):

DEBUG: Hello World

DEBUG: i=100, j=200

C、#操作符

如果我们在参数操作符的前面放置一个#,那么C语言的预处理器将使用该参数生成一个常数字符串,例如我们定义str如下:

#define str(x)  #x

如果在程序中输入语句

str(testing)

最终展开形式将会是

"testing"

而语句 printf(str(Programming in C is fun:\n));将被转换为:

printf("Programming in C is fun:\n");

D、##操作符

在宏定义中,这个操作符可以把两个符号连接起来。##操作符的前面或者后面可以是宏的参数,预处理器在展开宏的时候,将把该参数和##操作符前面或者后面的符号连接起来,以便创建一个新的符号。如:

#define printx(n) printf("%d\n", x##n)

语句中的字符串“x##n”的##操作符将前面和后面的记号连接起来,合成一个新的记号,因此下面的宏调用语句:

printf(20);

将被展开成如下形式:

printf("%i\n",x20);

如果你用过VTK,看过其头文件,你就会发现VTK的头文件中的函数和我们用到的函数不一样,其实并不是不一样,只是用了宏替换而已,如对球的操作函数-设定球心函数为:

void SetCenter (double, double, double);

但该头文件中的函数声明却是:

vtkGetVectorMacro(Center,double,3);

这里就是用了红替换而将下面的函数展开成上面的函数。

看下面的一个例子:

#include

#include

#define setMacro(c,x) set##c(x)

double setx(double a)

{

return a+2.0;

}

double sety(double a)

{

return a;

}

double *setxyz(double a)

{

double arr[3];

arr[0]=a+4.0;

arr[1]=a+5.0;

arr[2]=a+6.0;

return arr;

}

int main(int argc,char *argv[])

{

double a=5.0;

double b=setMacro(x,a);//等价于 b=setx(a);

double c=setMacro(y,a);//

printf("a=%lf\nb=%lf\nc=%lf\n",a,b,c);

double *xyz=malloc(3*sizeof(double));

xyz=setMacro(xyz,a);

printf("arr[0]=%f,arr[1]=%f,arr[2]=%f\n",xyz[0],xyz[1],xyz[2]);

return 0;

}

编译后执行的输出结果为:

a=5.000000

b=7.000000

c=5.000000

arr[0]=9.000000,arr[1]=10.000000,arr[2]=11.000000

上面的函数只要遇到setMacro(c,x)就将其替换成setc(x)的形式,并且不分析参数x的类型如何,如setMacro(x,a) 被替换成setx(a),setMacro(xyz,a)被替换成setxyz(a)执行。

当然了,你或许会说上面的代码不规范,的确,我只是作为一个例子拿过来用而已,说明如何使用宏替换函数。

宏处理语句的用法还有:#include 语句、条件编译语句(如#ifdef、#enif、#else和#ifndef语句)、#if和elif、#undef语句等,这里就不一一说明。

C语言使用define定义圆周率,C语言中的宏处理相关推荐

  1. C语言 define 定义函数 - C语言零基础入门教程

    目录 一.define 简介 二.define 定义函数 1.define 定义不带参数的函数 2.define 定义带参数的函数 三.define 定义函数陷阱 1.define 函数陷阱一 2.d ...

  2. C语言 define 定义常量 - C语言零基础入门教程

    目录 一.define 简介 二.define 实战 1.不使用 define 2.使用 define 3.使用 define 优点 三.猜你喜欢 零基础 C/C++ 学习路线推荐 : C/C++ 学 ...

  3. C语言——初识C语言(define定义常量和宏,指针,结构体)

    1.1define定义常量和宏 define    定义符号(定义常量) //define 定义标识符常量 #define MAX 1000 define    定义宏(宏是有参数的,参数用来替换) ...

  4. 【C语言】#define定义的标识符和宏

    目录 1.#define定义标识符 语法 2.#define定义宏 #define替换的规则 #与## #的用法: ##的用法: 宏的缺点

  5. c语言结构体定义坐标,C语言结构体定义的方法汇总

    什么是结构体? 在C语言中,结构体(struct)指的是一种数据结构,是C语言中聚合数据类型(aggregate data type)的一类.结构体可以被声明为变量.指针或数组等,用以实现较复杂的数据 ...

  6. c语言结构内部定义指针,C语言知识补漏(一)结构体指针以及位域定义

    一.结构体指针 typedef struct { unsigned long int DATA; unsigned long int DIRECTION; unsigned long int INTE ...

  7. c语言结构体定义坐标,C语言结构体定义的方式

    结构体是由不同数据类型组织在一起而构成的一种数据类型,因而一个结构体有多个数据项,每个数据项的类型可不相同. 1.结构体类型的说明 由于结构体类型不是C语言提供的标准类型,为了能够使用结构体类型,必须 ...

  8. c语言结构体定义蚂蚁,C语言结构体(struct)常见使用方法

    C语言结构体(struct)常见使用方法 C语言结构体(struct)常见使用方法 基本定义:结构体,通俗讲就像是打包封装,把一些有共同特征(比如同属于某一类事物的属性,往往是某种业务相关属性的聚合) ...

  9. php 如何宏定义,php – 在html中实现宏定义的方法

    也许显而易见,但C预处理器可以完成这项工作. index._html #define _em(a) a #define _image(a, b) #define _list(a, b, c) a \ ...

最新文章

  1. 对第三方 SDK 依赖冲突,重新打个包试试
  2. Linux memcached 安装
  3. vim中使用sed去除网上copy的源代码行号和空格
  4. 利物浦大学的对于学生多样性的保护的网站!有什么unbalanced issues 直接找这里就行!
  5. Ant Design Vue select下拉列表设置默认值
  6. svn备份遇到的问题
  7. composer 检查镜像_检查N元树中的镜像
  8. 为什么我放弃饿了么产品总监,却要从事自由职业?
  9. mysql qpstps测试_mysql操作日志
  10. LeetCode31.下一个排列 JavaScript
  11. asp.net控件开发基础二
  12. UnityVS(2012)安装教程
  13. Ftp客户端概要设计
  14. 提高智商、改善记忆力的120种绝佳方法!
  15. 在n1 ,魔百盒q5盒子上,实现惠普p1008系列的网络共享 打印和airprint服务
  16. vue中使用iview修改Cascader的默认数据
  17. ASP.NET Core 和 EF Core 系列教程——迁移
  18. 产品全生命周期的产品结构和配置管理构架
  19. 新浪微博授权登陆获取个人信息
  20. Linux 块设备之bio结构体

热门文章

  1. unity 只输入中英数_使用正则限制input框只能输入数字/英文/中文等等
  2. 周志华机器学习--模型评估与选择
  3. 微电网重构|基于群稀疏性的机会约束微电网重构(Matlab代码和Python代码实现)
  4. 初窥Java门径(下)
  5. 智慧工地助力建筑行业长期健康发展
  6. Ecovadis认证问题集
  7. C++ STL map I don't want it to sort!
  8. IP归属地在线查询平台 javaSE
  9. 基于C语言的新冠疫情通报系统设计与实现 报告+项目源码
  10. wordpress拒绝访问_拒绝访问。 (异常来自 HRESULT:0x80070005 (E_ACCESSDENIED))