回忆:#define的用法

ANSI C规定:#前可以有空格或者tab,#和指令其余部分之间也可以有空格,可以出现在任何地方,作用域从定义处到文件结尾。

因为预处理开始前,系统会删除反斜线和换行符的组合,故可以把指令扩展到几个物理行,这些物理行组成单个逻辑行。

//每个#define行(指逻辑的行):三部分组成
//指令本身   宏   替换列表(或主体)
#define     PI    3.141592653

宏分为类对象宏(代表值的宏)和类函数宏
宏的名字中间不能有空格,必须遵循c命名规则,从宏变成最终的替换文本叫宏展开,预处理器不进行计算,只是简单的文本替换

语言符号类型字符串和字符型字符串

系统把主体当作语言符号类型字符串,而不是字符型字符串,预处理器中的语言符号是宏定义主体里的单独的词,用空白字符把这些词分开。

#define SIX 2*2//定义里有一个语言符号,序列2*2
#define AAA 2     *     2//定义里有三个语言符号,2,*,3

若把主体解释为字符型字符串,预处理器用2    *     2替换AAA,额外的空格也算替换

若把主体解释为语言符号类型字符串,预处理器只用单个空白字符分割的三个语言符号去去替换AAA

2 * 2的空格只是分割主体语言符号的符号,不会都算(注意:不同编译器做法不一样)

重定义常量

开始把AAA定义为常量4,后来在该文件里,又把AAA定义为10,这叫重定义常量,不同编译器策略不一样,不过标准c规定:这是错误的,只允许新定义和旧定义完全相同!

//相同定义意味主体具有相同顺序的语言符号
#define A 2 * 3
#define A 2    *   3//两者等价,都是三个语言符号的主体

下面的定义被ANSI C认为不同

#define A 2*3//只有一个语言符号的主体,可以用#undef指令重新定义宏

在#define里使用参数——类函数宏

类函数宏:外形和作用和函数类似,可以使用参数,也是()括起来。一般要主体参数里都加上小括号来避免文本替换的错误发生。

#define  SQRT(x)  x*x
int main(void)
{
    int x = 2;
    printf("%d\n", SQRT(2));//4
    printf("%d\n", SQRT(4));//16
    printf("%d\n", SQRT(2 + x));//8
    printf("%d\n", SQRT(2 + 2));//没有打印16,而是8=2 + 2 * 2 + 2
    //一定主要,类函数宏也是文本替换,可以通过在主体里加圆括号来约束结合性

  //避免在宏里使用增量和减量运算符
    printf("%d\n", SQRT(++x));//16,++x*++x,x两次增量,一次在乘法前,一次在后
    printf("%d\n", x);//4
    //不同编译器处理不一样,4*4=16,这里x先两次自增到4,再乘。有的编译器不一样,故宏避免使用增量减量
    system("pause");
    return 0;
}

宏里的#和##运算符

#include <stdio.h>
#include <stdlib.h>
#define PSQR(X) printf("x的平方 = %d\n", ((X) * (X)));//注意这里的;是printf语句的分号
int main(void)
{
    PSQR(3);
    system("pause");
    return 0;
}

结果是 x 的平方 = 9

注意,printf引号里的x被看作是普通的文本,而不是一个可以被替换的语言符号!可以在类函数宏的替换部分,使用#运算符做预处理,这样普通文本转换为可以被替换的语言符号!如果x是宏参数,那么#x可以把参数名转换为相应的字符串处理,就可以输出3,而不是X!(该过程也叫字符串化)。

#define PSQR(X) printf(#X "的平方 = %d\n", ((X) * (X)));
int main(void)
{
    PSQR(3);
    system("pause");
    return 0;
}

3的平方 = 9

调用宏,用 ”3” 代替 #X ,标准C把这些字符串链接起来,产生最终结果。

#只可以用于类函数宏,而##运算符既可以用于类函数宏,也可以用到类对象宏。

##可以把两个语言符号组合为单个语言符号!

#define XNAME(n) X##n //类函数宏里,n是宏参数(一个语言符号),X是一个语言符号,加上##,两者变一个语言符号
#define PRINT_XN(n) printf("x" #n " = %d \n", X ## n);//注意这里X必须大写,因为XNAME里X大写了
int main(void)
{
    int XNAME(1) = 14;//相当于 int x1 = 14;
    PRINT_XN(1);
    system("pause");
    return 0;
}

打印 x1 = 14

可变宏

函数可以接收固定参数,也可以接收可变参数(printf函数)。同样宏也是这样。

注意:可变,字符串化是c的词汇,但是固定函数,固定宏,不变宏等不是C的词汇。

实现思想:宏定义的参数列表最后一个参数为省略号…(三个点),预定义宏__VA_ARGS__就可以用在被替换部分,说明省略号的含义。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define PR(X, ...) printf("可变宏:" #X  __VA_ARGS__ );//注意这里是两个下划线__
int main(void)
{
    double x = 48;
    double y;
    y = sqrt(x);
    //第一个参量对应宏的X,值为1,则#X 变为1,宏展开后成为:
    //printf("可变宏:" "1" "x = %g\n", x);
    //然后三个字符串被编译器连接为:
    //printf("可变宏:1x = %g\n", x);
    //最后指向输出
    PR(1, "x = %g\n", x);//__VA_ARGS__告诉了省略号代表了什么
    //注意:省略号只能代表最后一个参数!!!
    system("pause");
    return 0;
}

宏是用空间换取时间,函数是用时间换取空间,比如,使用宏100次,那么会在程序里插入100次宏代表的代码,浪费空间,但是速度很快。使用函数100次,程序只有一份函数的拷贝,节省空间,但是每次调用函数,都要压栈出栈,返回调用点,浪费时间!

简单函数就能处理的功能,一般用宏,或者内联函数。

宏名字不能有空格,必须大写(约定俗成的,提醒程序员这是宏),宏不检测类型只是简单的文本替换,好处是int类型,或者double类型等都能使用。

用圆括号括起来类函数宏里的每个参数,好习惯,避免文本替换造成逻辑混乱的错误。

辛苦的劳动,转载请注明出处,谢谢……

http://www.cnblogs.com/kubixuesheng/p/4314881.html

时间: 2024-08-31 00:45:16

回忆:#define的用法的相关文章

Linux c中define的用法小结_C 语言

define的用法只是一种纯粹的替换功能,宏定义的替换是预处理器处理的替换. 一:简单的宏定义用法 格式:#define 标识符 替换内容 替换的内容可以是数字,字符,字符串,特殊字符和空格,后面是什么内容就会替换成什么内容. 例如: #define  N   5 效果等同于 int  array [5]; int  array[N]; 同样效果: #define N = 5 int array[N];    效果等同于 int  array[= 5]; 同样效果: #define N   5;

typedef和#define的用法以及区别_C 语言

一.typedef的用法 在C/C++语言中,typedef常用来定义一个标识符及关键字的别名,它是语言编译过程的一部分,但它并不实际分配内存空间,实例像: typedef    int       INT;typedef    int       ARRAY[10];typedef   (int*)   pINT; typedef可以增强程序的可读性,以及标识符的灵活性,但它也有"非直观性"等缺点. 二.#define的用法 #define为一宏定义语句,通常用它来定义常量(包括无参

php中define用法实例_php技巧

本文实例讲述了php中define用法.分享给大家供大家参考.具体如下: <?php /* * define * */ /*第3个参数: * false -- 对大小写敏感(默认) * true -- 对大小写不敏感 * */ define("pai",3.14); define ("name","LiLei",true); function testfor($x) { for($a=$x;$a<=12;$a++) { echo &q

c-C语言中#define的问题

问题描述 C语言中#define的问题 我在学CUDA的时候看到库文件driver_type.h中的一个定义 typedef device_builtin enum cudaError cudaError_t; 看不懂这是什么意思. cudaError_t是新定义类型. cudaError的定义是:enum device_builtin cudaError{...} device_builtin是: #define device_builtin 我不明白这里的__device_builtin__

PHP中你应该知道的require()文件包含的正确用法_php技巧

以前看一些PHP框架源码的时候,很奇怪在文件包含的时候,会用dirname(__FILE__)来拼凑文件路径,不知道这样做有什么好处,后来终于发现了其中的缘由. 我们来看一个简单的例子: 有a,b,c三个php文件.a.php在网站根目录,b.php在b文件夹下--b/b.php,c.php在c文件夹下--c/c.php.有些混乱?看图就一目了然了: a.php 和 b.php 都包含了 c.php,最后 c.php 包含了d文件夹下的一个php文件--d/d.php. 我们先来看a.php:

js中 javascript:void(0) 用法详解_javascript技巧

javascript:void(0)表示不做任何动作.如: 复制代码 代码如下: <a href="javascript:void(0);" onclick="alert('ok');"></a>  这里表示这个链接不做跳转动作,执行onClick事件. 我想使用过ajax的都常见这样的代码: 复制代码 代码如下: <a href="javascript:doTest2();void(0);">here<

关于define与C 的内存_C 语言

问题1:#define到底存在程序的哪个区? 自己写了一个小程序验证一下第一个问题. 程序代码: <span style="font-size:18px;">#include <stdio.h> #include <STDLIB.H> #define kMAX 100 typedef struct { int ID; char * name; }Student; void test() { return; } //常量区,静态区,堆区,栈区,程序代码

跟我一起写 Makefile

陈皓 概述 -- 什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得要作一个好的和 professional的程序员,makefile还是要懂.这就好像现在有这么多的HTML的编辑器,但如果你想成为一个专业人士,你还是要了解 HTML的标识的含义.特别在Unix下的软件编译,你就不能不自己写makefile了,会不会写makefile,从一个侧面说明了一个人是否具备完 成大型工程的能力. 因为,makefile关系到

提前认识软件开发(11) localtime与GetLocalTime

在C语言中,有两个获取当前时间的函数:localtime和GetLocalTime.它们在诸如对账一类的程序中应用很广. 本文对localtime和GetLocalTime进行较为详细的介绍,并举例说明它们的用法. 1.前言 在C语言中,获取当前系统时间的操作时有发生.例如,在对账程序中,需要在对账文件名中加入当天的日期及时间.一般而言,经常使用的获取当前时间的函数有两个:localtime和GetLocalTime. 本文分别介绍了localtime和GetLocalTime函数,并举例说明了