define宏定义uoinxin

定义宏的作用一般是用一个短的名字代表一个长的字符串。

1)#define 标识符 字符串

这就是已经介绍过的定义符号常量。

如:#define PI 3.1415926

2)还可以用#define命令定义带参数的宏定义。其定义的一般形式为:

#define 宏名(参数表) 字符串

如:#define S(a, b) a*b  //定义宏S(矩形面积),a、b为宏的参数

使用的形式如下:    area=S(3, 2);用3、2分别代替宏定义中的形式参数a和b,即用3*2代替S(3, 2)。因此赋值语句展开为:    area=3*2;

由于C++增加了内置函数(inline),比用带参数的宏定义更方便,因此在C++中基本上已不再用#define命令定义宏了,主要用于条件编译中。

需要注意的就是在涉及运算或着其他一些情况下,要加上括号来避免结合律影响运算结果

如:

5*add(2,3),你期望的结果是25,但是,在不加括号的情况下 5*2+3 结果是30.

为了能够真正理解#define的作用,让我们来了解一下对C语言源程序的处理过程。当我们在一个集成的开发环境如Turbo C中将编写好的源程序进行编译时,实际经过了预处理、编译、汇编和连接几个过程。其中预处理器产生编译器的输出,它实现以下的功能:(1)文件包含    可以把源程序中的#include 扩展为文件正文,即把包含的.h文件找到并展开到#include 所在处。(2)条件编译    预处理器根据#if和#ifdef等编译命令及其后的条件,将源程序中的某部分包含进来或排除在外,通常把排除在外的语句转换成空行。(3)宏展开    预处理器将源程序文件中出现的对宏的引用展开成相应的宏 定义,即本文所说的#define的功能,由预处理器来完成。    经过预处理器处理的源程序与之前的源程序有所有不同,在这个阶段所进行的工作只是纯粹的替换与展开,没有任何计算功能,所以在学习#define命令时只要能真正理解这一点,这样才不会对此命令引起误解并误用。

在带参数的宏定义的使用中,极易引起误解。例如我们需要做个宏替换能求任何数的平方,这就需要使用参数,以便在程序中用实际参数来替换宏定义中的参数。一般学生容易写成如下形式:

按理说给的参数是2+2,所得的结果应该为4*4=16,但是错了,因为该程序的实际结果为8,仍然是没能遵循纯粹的简单替换的规则,又是先计算再替换 了。

在这道程序里,2+2即为area宏中的参数,应该由它来替换宏定义中的x,即替换成2+2*2+2=8了。那如果遵循(1)中的解决办法,把2+2 括起来,即把宏体中的x括起来,是否可以呢?#define area(x) (x)*(x),对于area(2+2),替换为(2+2)*(2+2)=16,可以解决。

但是对于area(2+2)/area(2+2)又会怎么样呢,有的学生一看到这道题马上给出结果,因为分子分母一样,又错了,还是忘了遵循先替换再计算的规则了,这道题替换后会变为 (2+2)*(2+2)/(2+2)*(2+2)即4*4/4*4按照乘除运算规则,结果为16/4*4=4*4=16,那应该怎么呢?解决方法是在整个宏体上再加一个括号,即#define   area(x) ((x)*(x)),不要觉得这没必要,没有它,是不行的。

如果是自己编程使用宏替换,则在使用简单宏定义时,当字符串中不只一个符号时,加上括号表现出优先级,如果是带参数的宏定义,则要给宏体中的每个参数加上括号,并在整个宏体上再加一个括号。

上面程序的这种做法对于非负数而言那就是没有问题的,比如,程序中的 变量 i=10,这个时候,调用宏得到的数据如下:

但是如何变量的数值是自加或者自减的操作的话,结果就不一样了。

得到的结果并不是 11 * 11 *11 = 1331这个数据,而是 1872。

当使用了 ++i 和 i++ 的时候,要特别注意在宏中是全部使用 ++i或者i++的,变成的格式如下

MUL(i++)  ((i++)*(i++)*(i++))

MUL(++i)    ((++i)*(++i)*(++i))

当 i  = 10的时候,MUL(i++)就是为  (i++)*(i++)*(i++)的计算结果,考虑到C/C++的运算符结合性,先计算第一个 i++,这是一个先计算后赋值的自加方式,那么这是后第一个 (i++)的数值待定为 10 ,那么第二个的i是因为第一个数据的 (i++)起了作用而变化的,这时候第二个(i++)的数值为11,然后加1,这时候 根据结合性,先计算前面两个数据,就是(i++) * (i++)的数值了,即为:10 * 11了,这时候的i数值是 12;然后计算第三个 i++的数值,这时候第三个i++中的i数值为 12,计算后再加1,也就是说,10 * 11 * 12之后,i= 12 的数值在进行i++变为 13了。所以  MUL(i++) = 10 * 11 * 12 = 1320。

MUL(++i)    ((++i)*(++i)*(++i))

当 i = 10的时候,MUL(++i)实际上也为 (++i)*(++i)*(++i)的方式,这时候先计算第一个 (++i),这是一个先计算后赋值的结合方式,那么 i = i+1 = 11;这时候准备计算第二个(++i)的时候,因为需要先计算后赋值,所以第二个 ++i 之后的数值为12,但是因为i属于同一个变量和属性,那么第一个i也会变成 12了,这时候结合性考虑应该是计算前两个(++i)的结果,再与第三个(++i)计算,即(++i)*(++i) = 12 * 12;然后,我们计算第三个(++i)的数值,由于前面第二个++i的i值,所以第三个++i即为 13,此时,12 * 12 * 13。

注意计算顺序:先计算前两个括号内的运算,然后再计算前两个括号的相乘结果。

有人可能顾虑,为什么最后不是13 * 13 * 13的呢?那不是最后都是13吗??  ------》其实这种想法是错误的,这必须先理解运算符的结合性。我们知道,当计算中遇到了括号的时候,我们先计算括号的内容,这是我们在数学中的惯性思维。但是对于计算机而言,计算机必须 有计算的优先级,也就是运算符的优先级问题。首先我们计算前面两个括号的内容,因为两个括号之间有乘号(*),所以计算前面两个(++i)之后,必须进行乘法计算,这就是优先级中的乘法计算,自左向右计算。所以结果变为了 12 * 12的最终结果在和第三个括号的(++i)计算,就是144 * (++ i) = 144 * 13;所以MUL(++i)的结果如下:

MUL(++i)=12*12*13=1872

慎用宏在计算方面的,但是宏的有点还是很多的,对于C语言来说,宏可以减少运行的时间。在C++中,宏由于不会对类型进行检查,安全性不够,所以建议使用const来进行使用,这样可以保证类型一致。

宏定义是用宏名来表示一个字符串,在宏展开时又以该字符串取代宏名,这只是一种简单的代换,字符串中可以含任何字符,可以是常数,也可以是表达式,预处理程序对它不作任何检查。如有错误,只能在编译已被宏展开后的源程序时发现。

宏定义不是说明或语句,在行末不必加分号,如加上分号则连分号也一起置换。

宏定义只是简单的字符串代换,是在预处理完成的,而typedef是在编译时处理的,它不是作简单的代换,而是对类型说明符重新命名。被命名的标识符具有类型定义说明的功能。

从形式上看这两者相似, 但在实际使用中却不相同。

下面用PIN1,PIN2说明变量时就可以看出它们的区别:

PIN1 a,b;在宏代换后变成:int *a,b;表示a是指向整型的指针变量,而b是整型变量。

PIN2 a,b;表示a,b都是指向整型的指针变量。因为PIN2是一个类型说明符。

由这个例子可见,宏定义虽然也可表示数据类型, 但毕竟是作字符代换。在使用时要分外小心,以避出错。

1. 带参宏定义中,宏名和形参表之间不能有空格出现。

2. 在带参宏定义中,形式参数不分配内存单元,因此不必作类型定义。而宏调用中的实参有具体的值。要用它们去代换形参,因此必须作类型说明。这是与函数中的情况不同的。在函数中,形参和实参是两个不同的量,各有自己的作用域,调用时要把实参值赋予形参,进行“值传递”。而在带参宏中,只是符号代换,不存在值传递的问题。

3. 在宏定义中的形参是标识符,而宏调用中的实参可以是表达式。

上例中第一行为宏定义,形参为y。程序第七行宏调用中实参为a+1,是一个表达式,在宏展开时,用a+1代换y,再用(y)*(y) 代换SQ,得到如下语句:sq=(a+1)*(a+1);这与函数的调用是不同的,函数调用时要把实参表达式的值求出来再赋予形参。而宏代换中对实参表达式不作计算直接地照原样代换。

4. 在宏定义中,字符串内的形参通常要用括号括起来以避免出错。

(3)#x,给x加双引号

char* str = ToString(123132);就成了str="123132";

2 得到指定地址上的一个字节或字

3 得到一个field在结构体(struct)中的偏移量

请参考文章:详解写宏定义:得到一个field在结构体(struct type)中的偏移量

ANSI C标准允许任何值为0的常量被强制转换成任何一种类型的指针,并且转换结果是一个NULL指针,因此((s*)0)的结果就是一个类型为s*的NULL指针。如果利用这个NULL指针来访问s的成员当然是非法的,但&(((s*)0)->m)的意图并非想存取s字段内容,而仅仅是计算当结构体实例的首址为((s*)0)时m字段的地址。聪明的编译器根本就不生成访问m的代码,而仅仅是根据s的内存布局和结构体实例首址在编译期计算这个(常量)地址,这样就完全避免了通过NULL指针访问内存的问题。

THE END
0.随机生成5位大小写字母或者数字随机生成5个字母'R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i', 'j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','r', '0','1','2','3','4','5','6','7','8','9'}; jvzquC41dnuh0lxfp0tfv8|cpiwjpp=663755<4ctvodnn4fgvgjn|4757864<71
1.打印出所有5个字符的可能组合根据以下条件写一段代码,打印出所有5个字符的可能组合: 1. 至少有一个大写字母 2. 至少有一个小写字母 3. 至少有一个数字 4.两个一样的数或者字母不能连在一起(比如 Haxa5是可以的,Haax5就不可以) publicstaticvoidprint(){ String upper[] = {"A","B","C","D","E","F","G","H","I"jvzquC41dnuh0lxfp0tfv8qkgtkmk8ftvkimg8igvcomu8=68::45>
2.JAVA:字符变形输入一个字符串,将其逆序,让每个字符按往后移动5个位置JAVA:字符变形 输入一个字符串,将其逆序,让每个字符按往后移动5个位置,(比如a后移5位为f)输出变换后的字符串 该博客展示了如何使用Java的Scanner类获取用户输入的字符串,然后将字符串翻转并输出。翻转过程通过遍历原始字符串的每个字符并从后向前拼接实现。之后,对翻转后的字符串进行字符编码的偏移操作,每个字符jvzquC41dnuh0lxfp0tfv8|gkzooa=:433::88ftvkimg8igvcomu86443:78>8
3.python小练习9(这些简单的题目你都会吗)printa负55 3: 下面2个变量 a = ‘1’ b = 2 print a + b 的结果是什么,为什么会出现这个结果,如果希望结果是3,要怎么操作? 答: TypeError: must be str, not int 不同类型不能相加 print(int(a) + b) AI写代码 1 4: 字符串: a = ‘abcd’, 用2个方法取出字母d jvzquC41dnuh0lxfp0tfv8RVdchz1jwvkerf1mjvckrt1@<;37:94
4.[编程]字符计数单词识别与字符串操作实践,本题要求编写程序,统计并输出某给定字符在给定字符串中出现的次数。 输入格式: 输入第一行给出一个以回车结束的字符串(少于80个字符);第二行输入一个字符。 输出格式: 在一行中输出给定字符在给定字符串中出现的次数。 输入样例: programmingisMorefun! jvzquC41dnuh0lxfp0tfv8f647666;>61cxuklqg1fkucrqu13964;>6;6
5.编程挑战题解析1. 给定等式 A B C D E 其中每个字母代表一个数字,且不同数字对应不 D F G 同字母。编程求出这些数字并且打出这个数字的 + D F G 算术计算竖式。 ─────── X Y Z D E 2. A、B、C、D、E五名学生有可能参加计算机竞赛,根据下列条件判断哪些 jvzquC41dnuh0lxfp0tfv8qkcpm97:64:1gsvrhng1jfvjnnu17739>29
6.PTA客观题(NO.10)F 1-4 指向数组元素的指针只可指向数组的首元素。 (1分) T F 1-5 对于已正确定义的二维数组a,*(a[i]+j)与a[i][j]的含义相同。 (1分) T F 1-6 以下定义了一个一维数组str,该数组可以存放81个字符型数据。 char str[81]; (1分) jvzquC41dnuh0lxfp0tfv8Tt|kkov8ftvkimg8igvcomu86442647<7
7.《编译原理》用例题理解给定文法 G[S]:(1)S->Af (2)S->Be (3)A->a (4)A->cA (5)B->b (6)B->dB 一键获取完整项目代码java 1 2 3 4 5 6 7 详解: 求(1)中的 Af 的 FIRST 集,注意,因为如果推出为空时用 ε,所以 A 后面的 f 是没用的,我们只分析 A 的第一个终结符的集。 jvzquC41dnuh0lxfp0tfv8vsa6626@=851gsvrhng1jfvjnnu1?1;A9597
8.C语言字符输入/输出22printf("请输入5个字符串: \n"); for(inti =0;i < num;i++){ fgets(*(st+i),SIZE,stdin); } } voidmenu(void){ printf("***\n"); printf("a.打印原字符 b.ASCII顺序打印\n"); printf("c.长度递增打印字符串 d.按第一个单词长度打印字符串\n"); printf("e.jvzquC41dnuh0lxfp0tfv8qkvvrfa|yctvup1jwvkerf1mjvckrt1:7:;;;5;>
9.《算法笔记》第2章C/C++快速入门printf("请输入一个字符串:"); scanf("%s", f); // char数组输入不加& printf("你的输入是:%d, %lld, %f, %lf, %c, %s", a, b, c, d, e, f); return 0; } 2.2.5 输入输出-3 #include<stdio.h> //notice: 如果要输入“3 4”这种用空格隔开的的两个数字,两个%d之间可以不jvzquC41dnuh0lxfp0tfv8vsa5>43?;771gsvrhng1jfvjnnu1716:<22:?
10.给定一个名称列表,其中一些名称仅包含一个字符要求返回一个逗号分print现在实际上是一个函数 1,打印多个参数 用逗号分隔,打印多个表达式 sep自定义分隔符,默认空格 end自定义结束字符串,默认换行 print("beyond",'yanyu',23)#结果为:beyond yanyu 23 AI写代码python 运行 1 a="beyond,"b="yanyu"c=23print(a,b,c)#结果为:beyond, yanyu 23print(a,b+',',c)#结果为jvzquC41dnuh0lxfp0tfv8vsa6738=5771gsvrhng1jfvjnnu1734<;343=
11.字符串排序程序本题要求编写程序,读入5个字符串,按由小到大的顺序输出。 输入格式: 输入为由空格分隔的5个非空字符串,每个字符串不包括空格、制表符、换行符等空白字符,长度小于80。 输出格式: 按照以下格式输出排序后的结果: Aftersorted: 每行一个字符串 AI写代码 jvzquC41dnuh0lxfp0tfv8|gkzooa=;57393:8ftvkimg8igvcomu86457?27@6
12.郑州大学C语言实验报告册答案2023郑州大学c语言程序设计实验报告5.编写一个用梯形法求一元函数f ( x ) f(x)f(x)在( a , b ) (a,b)(a,b)上积分近似值的函数过程。并就f ( x ) = s i n ( 2 x ) + x f(x)=sin(2x)+xf(x)=sin(2x)+x,当[ a , b ] = [ 0 , 3.14159 ] [a,b]=[0,3.14159][a,b]=[0,3.14159],小区间个数n=10和jvzquC41dnuh0lxfp0tfv8Sckstjnrq1ctzjeuj1fgzbkux135643A=84
13.JAVA中转义字符我不会游泳星号的转义:* ==> \u002A 加号的转义:+ ==> \u002B 问号的转义:? ==> \u003F 反斜杠的转义: ==> \u005C === 下面的程序使用了两个Unicode的转义字符,它们是用其十六进制代码来表示Unicode字符。那么,这个程序会打印什么呢? Java代码 public class EscapeRout{ public static void main(String[] ajvzquC41yy}/ewgnqiy/exr1cpzju8u192>95A=0jvsm
14.C++基础编程:字符数组操作与字符串处理选择题解析} //strlen求出字符串的长度,其实是字符串中字符的个数,不包括\0 程序运行后的输出结果是___C___ A)2 2 B)7 6 C)7 2 D)6 2 1.2、以下能正确定义一维数组的选项是___A___ A)int a[5]={0,1,2,3,4,5}; B)char a[]={0,1,2,3,4,5}; C)charjvzquC41dnuh0lxfp0tfv8~wcpxvkƒmk3490c{ykenk0fnyckny03<;355846
15.编译原理陈火旺版第三章课后题答案编译原理陈火旺第三版课后答案在 Concat 过程中,我们使用一个循环将 s1 中的字符逐一添加到返回字符串中,然后再将 s2 中的字符逐一添加到返回字符串中。 4. 用某种高级语言编写并调试一个完整的词法分析器。 5. 证明3.3.1中关于正规式的交换律、结合律等五个关系。 6.令 A、B 和 C 是任意正规式,证明以下关系成立: A∣A=A (A*)jvzquC41dnuh0lxfp0tfv8hcrv{sg<8551gsvrhng1jfvjnnu173:9;4;8:
16.数据结构习题假设某消息中只包含7个字符abcdefg假设某消息中只包含7个字符怡{a,b,c,d,e,f,g},折7个字符在消息中出现的次数为{5,24,8,17,34,4,13},利用哈夫曼树(最优二叉树)为该消息中的字符构造符合前缀编码要求的不等长编码。各字符的编码长度分别为A。 A.a:4,b:2,c:3,d:3,e:2,f:4,g:3 B.a:6,b:2,c:5,d:3,e:1,f:6,g:4 C.a:3,b:3,jvzquC41dnuh0lxfp0tfv8|gkzooa=::399:48ftvkimg8igvcomu86433>54<<
17.python随机条线45个字符python怎么从字符串中随机挑选5个字符一键获取完整项目代码python 1 2 3 4 5 6 7 8 9 10 11 运行这段代码会生成一个由4到5个随机字符组成的字符串,字符来自0-9和A-Z。每次运行可能会得到不同的结果。jvzquC41dnuh0lxfp0tfv8Iz{384;<6243<0c{ykenk0fnyckny03=;292?12
18.C语言编程作业#include<stdio.h>main(){floata,b,c,avg;scanf("%f,%f,%f",&a,&b,&c);printf("%.2f",avg=(a+b+c)/3);} 1 2 3 4 5 6 7 和、差、积、商与余数 输入2个整数 num1 和 num2,计算并输出它们的和、差、积、商与余数 #include<stdio.h>intmain(){inta,b;scanf("%d%d",&a,&b);prjvzquC41dnuh0lxfp0tfv8qqpiZUa]Y1ctzjeuj1fgzbkux134;22;:34
19.Linux基础教程(第二版)课后答案自主整理5、正则表达式的含义 file✳.c dir ??? Char[a-f].o *是指任意多个任意字符 ?是指单个字符 [a-f]是指这个位置可以是a到f的任意一个字符 6、cp,copy和mv 命令有何异同?能用copy作为复制文件的命令吗 答:cp命令复制一个文件,而原文件保持不变,这样文件个数就增加了;mv命令将文件从一个目录移到另一jvzquC41dnuh0lxfp0tfv8|gkzooa=8;82:258ftvkimg8igvcomu862:2662?: