精华内容
下载资源
问答
  • 对于以下宏定义
    千次阅读
    2021-08-04 13:08:58

    宏定义是C语言提供的三种预处理功能的其中一种,这三种预处理包括:宏定义、文件包含、条件编译。

    宏定义和操作符的区别:宏定义是替换,不做计算,也不做表达式求解。宏定义又称为宏代换、宏替换,简称“宏”。在 C 语言中,宏是产生内嵌代码的唯一方法。对于嵌入式系统而言,为了能达到性能要求,宏是一种很好的代替函数的方法。

    宏定义的格式:#DEFINE 标识符 字符串

    掌握"宏"概念的关键是“换”,一切以换为前提、做任何事情之前先要换,准确理解之前就要“换”,即在对相关命令或语句的含义和功能作具体分析之前就要换。

    定义宏需要注意以下几点:

    (1)宏名一般用大写;

    (2)使用宏可提高程序的通用性和易读性,减少不一致性,减少输入错误和便于修改。例如:数组大小常用宏定义;

    (3)预处理是在编译之前的处理,而编译工作的任务之一就是语法检查,预处理不做语法检查;

    (4)宏定义末尾不加分号;

    (5)宏定义写在函数的花括号外边,作用域为其后的程序,通常在文件的最开头;

    (6)可以用#undef命令终止宏定义的作用域;

    (7)宏定义允许嵌套;

    (8)字符串( " " )中永远不包含宏;

    (9)宏定义不分配内存,变量定义分配内存;

    (10)宏定义不存在类型问题,它的参数也是无类型的。

    在C语言/类C语言环境中,宏的作用有如下几种:

    1.取代Magic Number

    这个作用在嵌入式开发时太重要了。一个SoC 50多页的datasheet,上百个寄存器的位操作,如果没有很好的语义宏定义,调程序查手册绝对是崩溃的节奏!

    2.防止重复定义

    #ifndef XXXX

    #define XXXX

    #endif

    3.快速控制代码编译

    #define SIMULATION_DEBUG 1

    #if SIMULATION_DEBUG

    use simulated data

    #else

    real data

    #endif

    4.编译系统控制链

    在某些系统下,可以把宏定义传递给编译器,从而通过编译脚本(makefile)来控制编译选项,例如,配合上面代码,就可以在Makefile里定义:

    CDEFINES=$(CDEFINES) /SIMULATION_DEBUG

    说到编译,自然还要提一下 ANSI C中预定义的几个非常有用的编译宏:

    • _ L I N E _

    • _ F I L E _

    • _ D A T E _

    • _ T I M E _

    • _ S T D C _

    例如

    #define DEBUGMSG(msg,date) printf(msg);

    printf(“%d%d%d”,date,_LINE_,_FILE_)

    5.使用typedef

    C语言下typedef也是属于宏定义,我会告诉你C语言下struct+typedef+函数指针可以做到面向对象的继承,重载和多态吗?(有兴趣可以看一下MFC的源码实现,把传统的C风格的Windows API各种包装修饰和装逼。)

    typedef int (*PFFunc1)(int);

    6.简化操作

    得到一个字的高位和低位字节

    #define WORD_LO(xxx) ((byte) ((word)(xxx) & 255))

    #define WORD_HI(xxx) ((byte) ((word)(xxx) >> 8))

    更多相关内容
  • 宏定义是比较常用的预处理指令,即使用“标识符”来表示“替换列表”中的内容。标识符称为宏名,在预处理过程中,预处理器会把源程序中所有宏名,替换成宏定义中替换列表中的内容。常见的宏定义有两种,不带参数的...

    宏定义是比较常用的预处理指令,即使用“标识符”来表示“替换列表”中的内容。标识符称为宏名,在预处理过程中,预处理器会把源程序中所有宏名,替换成宏定义中替换列表中的内容。

    常见的宏定义有两种,不带参数的宏定义和带参数的宏定义。

    无参宏定义

    无参数宏定义的格式为:

    #define 标识符 替换列表

    替换列表可以是数值常量、字符常量、字符串常量等,故可以把宏定义理解为使用标识符表示一常量,或称符号常量。

    说明:

    1) # 可以不在行首,但只允许它前面有空格符。例如:

    #define PI 3.1416 //正确,该行#前允许有空格

    int a;#define N 5 //错误,该行#前不允许有空格外的其他字符

    2) 标识符和替换列表之间不能加赋值号 =,替换列表后不能加分号

    #define N =5 //虽语法正确,但预处理器会把N替换成=5

    int a[N]; //错误,因为宏替换之后为 int a[=5];

    宏定义不是语句,是预处理指令,故结尾不加分号。如果不小心添加了分号,虽然有时该宏定义没问题,但在宏替换时,可能导致 C 语法错误,或得不到预期结果。例如:

    #define N 5; //虽语法正确,但会把N替换成5;

    int a[N]; //语法错误,宏替换后,为int a[5;];错误

    3) 由于宏定义仅是做简单的文本替换,故替换列表中如有表达式,必须把该表达式用括号括起来,否则可能会出现逻辑上的“错误”。例如:

    #define N 3+2

    int r=N*N;

    宏替换后为:

    int r=3+2*3+2; //r=11

    如果采用如下形式的宏定义:

    #define N (3+2)

    int r=N*N;

    则宏替换后,为:

    int r=(3+2)*(3+2); //r=25

    4) 当替换列表一行写不下时,可以使用反斜线\作为续行符延续到下一行。例如:

    #define USA "The United \

    States of \

    America"

    该宏定义中替换列表为字符串常量,如果该串较长,或为了使替换列表的结构更清晰,可使用续行符 \ 把该串分若干行来写,除最后一行外,每行行尾都必须加续行符 \。

    如果调用 printf 函数,以串的形式输出该符号常量,即:

    printf("%s\n",USA);

    则输出结果为:The United States of America

    注意:续行符后直接按回车键换行,不能含有包括空格在内的任何字符,否则是错误的宏定义形式。

    带参宏定义

    带参数的宏定义格式为:

    #define 标识符(参数1,参数2,...,参数n) 替换列表

    例如,求两个参数中最大值的带参宏定义为:

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

    当有如下语句时:

    int c=MAX(5,3);

    预处理器会将带参数的宏替换成如下形式:

    int c=((5)>(3)?(5) : (3));

    故计算结果c=5。

    删除宏定义的格式为:

    #undef 标识符

    说明:

    1) 标识符与参数表的左括号之间不能有空格,否则预处理器会把该宏理解为普通的无参宏定义,故以下是错误的带参宏定义形式。

    #define MAX (a,b) ( (a) > (b) ? (a) : (b) ) //错误的带参宏定义格式

    2) 宏替换列表中每个参数及整个替换列表,都必须用一对小括号 () 括起来,否则可能会出现歧义。

    【例 1】以下程序试图定义求两个参数乘积的宏定义,欲使用该宏求 3 与 6 的乘积,分析该程序能否实现预期功能,如果不能,请给出修改方案。

    #include

    #define MUL(a,b) (a*b)

    int main (void)

    {

    int c;

    c=MUL(3,5+1);

    printf("c=%d\n",c);

    return 0;

    }

    分析:

    1) 由于该宏定义中的替换列表中的参数没有加括号,故宏调用时,如果参数是个表达式,可能会出现歧义,得不到预期结果。

    本例中宏调用 c=MUL(3,5+1); 会替换成 c=(3*5+1)=16;,与预期功能不符。

    2) 虽然把宏调用时的参数 5+1 括起来,可达到题目要求的效果,但这属于治标不治本。为统一编程规范,把替换列表中的每个参数均加括号,整个替换列表也加括号。

    同时,为达到标本兼治,在宏定义时,除单一值参数外,应显式加括号。

    修改代码为:

    #include

    #define MUL(a,b) ((a)*(b))//修改处1

    int main (void)

    {

    int c;

    c=MUL(3,(5+1);//修改处2

    printf("c=%d\n",c);

    return 0;

    }

    带参宏定义 VS 函教调用

    接下来将从调用发生时间、参数类型检查、参数是否需要空间、运行速度等几个主要方面进行对比分析带参宏定义与函数调用的差异。

    调用发生的时间

    在源程序进行编译之前,即预处理阶段进行宏替换;而函数调用则发生在程序运行期间。

    参数类型检查

    函数参数类型检查严格。程序在编译阶段,需要检查实参与形参个数是否相等及类型是否匹配或兼容,若参数个数不相同或类型不兼容,则会编译不通过。

    在预处理阶段,对带参宏调用中的参数不做检查。即宏定义时不需要指定参数类型,既可以认为这是宏的优点,即适用于多种数据类型,又可以认为这是宏的一个缺点,即类型不安全。故在宏调用时,需要程序设计者自行确保宏调用参数的类型正确。

    参数是否需要空间

    函数调用时,需要为形参分配空间,并把实参的值复制一份赋给形参分配的空间中。而宏替换,仅是简单的文本替换,且替换完就把宏名对应标识符删除掉,即不需要分配空间。

    执行速度

    函数在编译阶段需要检查参数个数是否相同、类型等是否匹配等多个语法,而宏替换仅 是简单文本替换,不做任何语法或逻辑检查。

    函数在运行阶段参数需入栈和出栈操作,速度相对较慢。

    代码长度

    由于宏替换是文本替换,即如果需替换的文本较长,则替换后会影响代码长度;而函数不会影响代码长度。

    故使用较频繁且代码量较小的功能,一般采用宏定义的形式,比采用函数形式更合适。前面章节频繁使用的 getchar(),准确地说,是宏而非函数。

    为了使该宏调用像函数调用,故把该宏设计成了带参数的宏定义:

    #define getchar() getc(stdin)

    故调用该宏时,需要加括号,即传空参数:getchar()。

    展开全文
  • C语言宏定义

    千次阅读 2020-12-29 11:24:09
    C语言宏定义C语言既具有高级语言的功能,又具有低级语言的许多功能。那么大家知道C语言宏定义是怎样的呢?下面一起来看看!宏定义是预处理命令的一种,它允许用一个标识符来表示一个字符串。先看一个例子:#include#...

    C语言宏定义

    C语言既具有高级语言的功能,又具有低级语言的许多功能。那么大家知道C语言宏定义是怎样的呢?下面一起来看看!

    宏定义是预处理命令的一种,它允许用一个标识符来表示一个字符串。先看一个例子:

    #include#define N 100int main(){ int sum = 20 + N; printf("%d

    ", sum); return 0;}

    运行结果:

    120

    该示例中的语句int sum = 20 + N;,N被100代替了。

    #define N 100就是宏定义,N为宏名,100是宏的内容。在编译预处理时,对程序中所有出现的“宏名”,都用宏定义中的字符串去代换,这称为“宏代换”或“宏展开”。

    宏定义是由源程序中的宏定义命令#define完成的,宏代换是由预处理程序完成的。

    宏定义的一般形式为:

    #define 宏名 字符串

    #表示这是一条预处理命令,所有的预处理命令都以#开头。define是预处理命令。宏名是标识符的一种,命名规则和标识符相同。字符串可以是常数、表达式等。

    这里所说的字符串是一般意义上的字符序列,不要和C语言中的`字符串等同,它不需要双引号。

    程序中反复使用的表达式就可以使用宏定义,例如:

    #define M (n*n+3*n)

    它的作用是指定标识符M来代替表达式(y*y+3*y)。在编写源程序时,所有的(y*y+3*y)都可由M代替,而对源程序编译时,将先由预处理程序进行宏代换,即用(y*y+3*y)表达式去替换所有的宏名M,然后再进行编译。

    将上面的例子补充完整:

    #include#define M (n*n+3*n)int main(){ int sum, n; printf("Input a number: "); scanf("%d", &n); sum = 3*M+4*M+5*M; printf("sum=%d

    ", n); return 0;}

    运行结果:

    Input a number: 10↙

    sum=1560

    上面的程序中首先进行宏定义,定义M来替代表达式(n*n+3*n),在sum=3*M+4*M+5*M中作了宏调用。在预处理时经宏展开后该语句变为:

    sum=3*(n*n+3*n)+4*(n*n+3*n)+5*(n*n+3*n);

    需要注意的是,在宏定义中表达式(n*n+3*n)两边的括号不能少,否则会发生错误。如当作以下定义后:

    #difine M n*n+3*n

    在宏展开时将得到下述语句:

    s=3*n*n+3*n+4*n*n+3*n+5*n*n+3*n;

    这相当于:

    3n2+3n+4n2+3n+5n2+3n

    这显然是不正确的。所以进行宏定义时要注意,应该保证在宏代换之后不发生错误。

    对宏定义的几点说明

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

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

    3) 宏定义必须写在函数之外,其作用域为宏定义命令起到源程序结束。如要终止其作用域可使用#undef命令。例如:

    #define PI 3.14159int main(){ // Code return 0;}#undef PIvoid func(){ // Code}

    表示PI只在main函数中有效,在func中无效。

    4) 宏名在源程序中若用引号括起来,则预处理程序不对其作宏代换,例如:

    #include#define OK 100int main(){ printf("OK

    "); return 0;}

    运行结果:

    OK

    该例中定义宏名OK表示100,但在 printf 语句中 OK 被引号括起来,因此不作宏代换,而作为字符串处理。

    5) 宏定义允许嵌套,在宏定义的字符串中可以使用已经定义的宏名,在宏展开时由预处理程序层层代换。例如:

    #define PI 3.1415926

    #define S PI*y*y /* PI是已定义的宏名*/

    对语句:

    printf("%f", S);

    在宏代换后变为:

    printf("%f", 3.1415926*y*y);

    6) 习惯上宏名用大写字母表示,以便于与变量区别。但也允许用小写字母。

    7) 可用宏定义表示数据类型,使书写方便。例如:

    #define UINT unsigned int

    在程序中可用UINT作变量说明:

    UINT a, b;

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

    请看下面的例子:

    #define PIN1 int *

    typedef (int *) PIN2;

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

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

    PIN1 a,b;

    在宏代换后变成:

    int *a,b;

    表示a是指向整型的指针变量,而b是整型变量。然而:

    PIN2 a,b;

    表示a、b都是指向整型的指针变量。因为PIN2是一个类型说明符。由这个例子可见,宏定义虽然也可表示数据类型, 但毕竟是作字符代换。在使用时要分外小心,以避出错。

    展开全文
  • C++宏定义详解

    2021-03-29 10:24:04
    宏定义 作用:把一个标识符(宏名)定义为字符串(替换文本),便于程序修改,同时使函数模块化,提高运行效率。 形式:简单宏定义,带参数宏定义 c语言源程序处理过程:预处理、编译、汇编和连接 其中预处理...

    宏定义

    作用:把一个标识符(宏名)定义为字符串(替换文本),便于程序修改,同时使函数模块化,提高运行效率。

    形式:简单宏定义带参数宏定义

    c语言源程序处理过程:预处理、编译、汇编和连接

    其中预处理过程包括宏展开,所以宏定义先宏展开后编译

    一、#define的基本用法

    #define是C语言中提供的宏定义命令,其主要目的是为程序员在编程时提供一定的方便,并能在一定程度上提高程序的运行效率。

    1 #define命令剖析

    1.1   #define的概念
    #define命令是C语言中的一个宏定义命令,它用来将一个标识符定义为一个字符串,该标识符被称为宏名,被定义的字符串称为替换文本。该命令有两种格式:一种是简单的宏定义,另一种是带参数的宏定义。
    (1)简单的宏定义:

    #define <宏名> <字符串>

    例: #define PI 3.1415926

    (2) 带参数的宏定义

    #define <宏名> (<参数表>) <宏体>

    例: #define A(x) x

    一个标识符被宏定义后,该标识符便是一个宏名。这时,在程序中出现的是宏名,在该程序被编译前,先将宏名用被定义的字符串替换,这称为宏替换,替换后才进行编译,宏替换是简单的替换。

    1.2 宏替换发生的时机

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

    2 #define使用中的常见问题解析

    2.1 简单宏定义使用中出现的问题

    在简单宏定义的使用中,当替换文本所表示的字符串为一个表达式时,容易引起误解和误用。如下例:

    #define N 2+2
    void main()
    {
       int a=N*N;
       printf(“%d”,a);
    }

    (1) 出现问题:

    在此程序中存在着宏定义命令,宏N代表的字符串是2+2,在程序中有对宏N的使用,一般同学在读该程序时,容易产生的问题是先求解N为2+2=4,然后在程序中计算a时使用乘法,即N*N=4*4=16,其实该题的结果为8,为什么结果有这么大的偏差?

    (2) 问题解析:

    如1节所述,宏展开是在预处理阶段完成的,这个阶段把替换文本只是看作一个字符串,并不会有任何的计算发生,在展开时是在宏N出现的地方 只是简单地使用串2+2来代替N,并不会增添任何的符号,所以对该程序展开后的结果是a=2+2*2+2,计算后=8,这就是宏替换的实质,如何写程序才能完成结果为16的运算呢?

    (3)解决办法:

    /*将宏定义写成如下形式*/
    #define N (2+2)
    /*这样就可替换成(2+2)*(2+2)=16*/

    2.2 带参数的宏定义出现的问题

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

    #define area(x) x*x
    /*这在使用中是很容易出现问题的,看如下的程序*/
    void main()
    {
        int y = area(2+2);
        printf(“%d”,y);
    }

    按理说给的参数是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)),不要觉得这没必要,没有它,是不行的。
    要想能够真正使用好宏定义,那么在读别人的程序时,一定要记住先将程序中对宏的使用全部替换成它所代表的字符串,不要自作主张地添加任何其他符号,完全展开后再进行相应的计算,就不会写错运行结果。

    如果是自己编程使用宏替换,则在使用简单宏定义时,当字符串中不只一个符号时,加上括号表现出优先级,如果是带参数的宏定义,则要给宏体中的每个参数加上括号,并在整个宏体上再加一个括号。看到这里,不禁要问,用宏定义这么麻烦,这么容易出错,可不可以摒弃它, 那让我们来看一下在C语言中用宏定义的好处吧。

    如:

    #include <iostream.h>
    #define product(x)    x*x
    int main()
    {
        int i=3;
        int j,k;
        j = product(i++);
        cout<<"j="<<j<<endl;
        cout<<"i="<<i<<endl;
        k = product(++i);
        cout<<"k="<<k<<endl;
        cout<<"i="<<i<<endl;
        return 0;
    }

    依次输出结果:

    j=9;i=5;k=49;i=7

    3 宏定义的优点

    (1)   方便程序的修改

    使用简单宏定义可用宏代替一个在程序中经常使用的常量,这样在将该常量改变时,不用对整个程序进行修改,只修改宏定义的字符串即可,而且当常量比较长时, 我们可以用较短的有意义的标识符来写程序,这样更方便一些。我们所说的常量改变不是在程序运行期间改变,而是在编程期间的修改,举一个大家比较熟悉的例子,圆周率π是在数学上常用的一个值,有时我们会用3.14来表示,有时也会用3.1415926等,这要看计算所需要的精度,如果我们编制的一个程序中 要多次使用它,那么需要确定一个数值,在本次运行中不改变,但也许后来发现程序所表现的精度有变化,需要改变它的值, 这就需要修改程序中所有的相关数值,这会给我们带来一定的不便,但如果使用宏定义,使用一个标识符来代替,则在修改时只修改宏定义即可,还可以减少输入 3.1415926这样长的数值多次的情况,我们可以如此定义 #define   pi   3.1415926,既减少了输入又便于修改,何乐而不为呢?

    (2) 提高程序的运行效率

    使用带参数的宏定义可完成函数调用的功能,又能减少系统开销,提高运行效率。正如C语言中所讲,函数的使用可以使程序更加模块化,便于组织,而且可重复利用,但在发生函数调用时,需要保留调用函数的现场,以便子函数执行结束后能返回继续执行,同样在子函数执行完后要恢复调用函数的现场,这都需要一定的时间,如果子函数执行的操作比较多,这种转换时间开销可以忽略,但如果子函数完成的功能比较少,甚至于只完成一点操作,如一个乘法语句的操作,则这部分转换开销就相对较大了,但使用带参数的宏定义就不会出现这个问 题,因为它是在预处理阶段即进行了宏展开,在执行时不需要转换,即在当地执行。宏定义可完成简单的操作,但复杂的操作还是要由函数调用来完成,而且宏定义所占用的目标代码空间相对较大。所以在使用时要依据具体情况来决定是否使用宏定义。
    4 结语

    本文对C语言中宏定义#define在使用时容易出现的问题进行了解析,并从C源程序处理过程的角度对#define的处理进行了分析,也对它的优点进行 了阐述。只要能够理解宏展开的规则,掌握使用宏定义时,是在预处理阶段对源程序进行替换,只是用对应的字符串替换程序中出现的宏名,这样就可在正确使用的 基础上充分享受使用宏定义带来的方便和效率了。

    二、define中的三个特殊符号:#,##,#@

    #define Conn(x,y) x##y
    #define ToChar(x) #@x
    #define ToString(x) #x

    (1)x##y表示什么?表示x连接y,举例说:

    int n = Conn(123,456); /* 结果就是n=123456;*/
    char* str = Conn("asdf", "adf"); /*结果就是 str = "asdfadf";*/

    (2)再来看#@x,其实就是给x加上单引号,结果返回是一个const char。举例说:

    char a = ToChar(1);//结果就是a='1';

    做个越界试验char a = ToChar(123);结果就错了;
    但是如果你的参数超过四个字符,编译器就给给你报错了!

    error C2015: too many characters in constant   :P

    (3)最后看看#x,估计你也明白了,他是给x加双引号

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

    三、常用的一些宏定义

    1 防止一个头文件被重复包含 

    #ifndef BODYDEF_H 
    #define BODYDEF_H 
     //头文件内容 
    #endif

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

    #define MEM_B(x) (*((byte *)(x))) 
    #define MEM_W(x) (*((word *)(x)))

    用法如下:

    #include <iostream>
    #include <windows.h>
    
    #define MEM_B(x) (*((byte*)(x)))
    #define MEM_W(x) (*((WORD*)(x)))
    
    int main()
    {
        int bTest = 0x123456;
        byte m = MEM_B((&bTest));/*m=0x56*/
        int n = MEM_W((&bTest));/*n=0x3456*/
        return 0;
    }

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

    #define OFFSETOF(type, field) ((size_t) &((type *)0)->field)

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

    4 得到一个结构体中field所占用的字节数 

    #define FSIZ(type, field) sizeof(((type *)0)->field)

    5 得到一个变量的地址(word宽度) 

    #define B_PTR(var) ((byte *)(void *)&(var)) 
    #define W_PTR(var) ((word *)(void *)&(var))

    6 将一个字母转换为大写

    #define UPCASE(c) (((c)>=''a'' && (c)<=''z'') ? ((c)-0x20) : (c))

    7 判断字符是不是10进值的数字

    #define DECCHK( c ) ((c) >= ''0'' && (c) <= ''9'')

    8 判断字符是不是16进值的数字 

    #define HEXCHK( c ) ( ((c) >= ''0'' && (c) <= ''9'') ||((c) >= ''A'' && (c) <= ''F'') ||((c) >= ''a'' && (c) <= ''f'') )

    9 防止溢出的一个方法

    #define INC_SAT( val ) (val = ((val)+1 > (val)) ? (val)+1 : (val))

    10 返回数组元素的个数 

    #define ARR_SIZE( a ) ( sizeof( (a) ) / sizeof( (a[0]) ) )

    11 使用一些宏跟踪调试

    ANSI标准说明了五个预定义的宏名。它们是: 

    _LINE_ /*(两个下划线),对应%d*/
    _FILE_ /*对应%s*/
    _DATE_ /*对应%s*/
    _TIME_ /*对应%s*/

     

    展开全文
  • 宏定义有无参数宏定义和带参数宏定义两种。 无参数的宏定义的一般形式为 # define 标识符 字符序列 其中# define之后的标识符称为宏定义名(简称宏名),要求宏名与字符序列之间用空格符分隔。这种宏定义要求编译...
  • C语言宏定义详解

    千次阅读 2022-06-01 22:28:12
    C语言宏定义详解
  • 宏定义常用知识点

    2021-01-14 08:59:05
    构建较长的字符串是续行的常见用途, 还有一个作用是定义跨行的。 如果我们不使用反斜杠,当我们试图初始化一个跨多行的字符串是,c语言编译器就会发出警告。如下面的语句所示: char letters[] = {...
  • 比较全面的宏定义解析

    千次阅读 2021-04-18 09:08:48
    宏定义宏定义是C提供的三种预处理功能的其中一种,这三种预处理包括:宏定义、文件包含、条件编译。参数不带参数宏定义又称为宏代换、宏替换,简称“宏”。格式:#define 标识符 字符串其中的标识符就是所谓的符号...
  • 这几天在整理和生产EMC单片机程序的一些,发现这东西真的是好用得超乎了想象,大大的简化了写程序时的重复劳动。以下以 EM78P260为主,其实其他型号大通小异,注意修改一下寄存器就可以。
  • 宏定义是C提供的三种预处理功能的其中一种,这三种预处理包括:宏定义、文件包含、条件编译。1.不带参数的宏定义宏定义又称为宏代换、宏替换,简称“宏”。格式: #define 标识符 字符串其中的标识符就是所谓的...
  • 宏定义函数

    千次阅读 多人点赞 2020-08-29 18:56:39
    宏定义的优点很多,但我个人理解宏定义最明显的优点就是增加代码的可读性。求圆的面积, 用“PI * r* r”比 “3.14人r”的可读性就强很多了。 #define PI 3.14 float circleArea(float r) { return PI * r * r; } ...
  • 本篇博客承上启下,进一步介绍 宏定义的各种使用方法和基本的注意点,为后篇 宏定义的具体应用打下基础,主要涉及 宏注释、宏定义的执行顺序、宏定义的有效范围以及该如何使用宏定义宏定义使用的基本注意点,了解...
  • 宏定义#define

    千次阅读 多人点赞 2021-11-30 12:40:24
    ❀不带参数的宏定义 1.宏定义指令#define: 用来定义一个标识符和一个字符串,以这 个标识符来代表这个字符串,在程序中每次遇到该标识符时就用所定义的字符串替换它。 2.宏定义的作用: 相当于给指定的字符串起一个...
  • 宏定义有无参数宏定义和带参数宏定义两种。无参数的宏定义的一般形式为 # define 标识符 字符序列其中# define之后的标识符称为宏定义名(简称宏名),要求宏名与字符序列之间用空格符分隔。这种宏定义要求编译预处理...
  • C语言的宏定义分析

    2021-05-21 16:32:41
    C语言的宏定义分析引导语:你了解C语言吗,知道C语言的宏定义是什么吗,以下是百分网小编分享给大家的C语言的'宏定义分析,欢迎阅读!C语言中,预处理器功能:1. #include <>or" " 的头文件替换2.#define 对象...
  • 51单片机的C语言宏定义应用.doc

    千次阅读 2021-05-20 17:14:01
    1、预编译处理是单片机C语言程序设计中经常用到的一种方法。通过一些预处理命令可以为C语言本身提供许多功能和符号的扩充,增强C语言程序的灵活性和方便...标识符称为宏名,进行过宏定义后,宏定义语句以下的程序里...
  • C语言可变参数宏定义方法

    千次阅读 2021-05-23 09:26:48
    http://blog.csdn.net/skyflying2012/article/details/384367112014在GNU C中,可以接受可变数目的参数,就象函数一样,例如:12#definepr_debug(fmt,arg...) \printk(KERN_DEBUGfmt, ##arg)用可变参数(variadic ...
  • C宏定义中的特殊用法在分析一些C源码时,经常会遇到各种宏定义操作,本文即总结一下C语言宏定义中常见的预定义宏、调试宏;宏的条件编译用法及特殊的宏关键字用法。#undef 限定宏的作用域一般来讲宏的作用域从 #...
  • 宏定义

    2022-04-01 23:35:44
    条件编译在宏定义中,字符串内的形参通常要用括号括起来以避免出错。一上例中的宏定义中 (y)*(y)表达式的y 都用括号括起来,因此结果是正确的。如果去掉括号,含义有可能改变 应该为((y)*(y)) 他仅仅是替换!!!...
  • Qt宏定义

    千次阅读 2019-08-13 20:07:57
    //在qglobal.h中,我们可以看到以下两句胡宏定义 # define QT_BEGIN_NAMESPACE namespace QT_NAMESPACE { # define QT_END_NAMESPACE } QT_BEGIN_NAMESPACE class QAction; class QMenu; class QPlainTextEdi...
  • C/C++宏定义

    千次阅读 2022-01-01 17:21:06
    其中与相关的操作在预处理过程中完成,预处理包含以下几个过程: (1)、文件包含 把源程序中#include包含的头文件扩展到文件正文,即把包含的.h文件找到并展开到#include所在的位置。 (2)、条件编译 预处理器...
  • 简单分析带参数宏定义

    千次阅读 2021-05-20 06:07:52
    相信学过C语言的同学都对C语言中的宏定义有一定的了解,而在实际编写程序时往往程序员都会加入带参数的宏,那么究竟什么是带参数的宏定义呢?下面课课家笔者就为大家介绍C语言中带参数的宏定义。在C语言中,通常允许...
  • 字符串常量与宏定义

    2021-04-20 11:43:46
    文章目录字符串常量常量和字符常量的区别:宏定义注意以下几点宏定义表示数据类型和用typedef定义数据说明符的区别:带参宏定义注意 字符串常量 字符串常量是由一对双引号括起来的字符序列 例如:“CHINA”,"$12.5...
  • 宏定义和函数

    2022-02-27 12:08:45
    #define执行查找替换,#if可以区分是否编译,#undef可以反定义,也就是取消#define宏定义的东西,#end并没有这玩意,只有#endif,故选D。 前三个是常用宏,分别是:打印所在文件、打印编译时间、打印编译日期。除...
  • 本文通过介绍一个实际的项目问题场景,介绍了一种C语言中宏定义的技巧写法,希望能借此给大家提起对宏定义的好奇心,一起来发现宏定义的各种奥秘吧。
  • C++中的宏定义详解

    千次阅读 2021-01-21 14:20:19
    转载自:C++中的宏定义和C++宏定义详解 一、#define解析 #define是C语言中提供的宏定义命令,其主要目的是为程序员在编程时提供一定的方便,并能在一定程度上提高程序的运行效率,但学生在学习时往往不能 理解该...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 167,988
精华内容 67,195
热门标签
关键字:

对于以下宏定义