精华内容
下载资源
问答
  • define在C语言中用法

    万次阅读 多人点赞 2018-07-21 17:19:54
    无非就是定义一个替换的量,好比#define PI 3.1415926,这样的功能,再深一点就是写一个类似函数的定义,好比#define MAX(a,b) ((a) > (b) ? (a) : (b))这样的功能,再问一下宏是什么?无非就是预处理阶段所...

    原来以为什么是宏?无非就是定义一个替换的量,好比#define PI 3.1415926,这样的功能,再深一点就是写一个类似函数的定义,好比#define MAX(a,b) ((a) > (b) ? (a) : (b))这样的功能,再问一下宏是什么?无非就是预处理阶段所要展开的乱七八糟的东西,其实也就知道这么点,当看了Linux Kernel Code,其实会发现自己懂得那些其实都是皮毛,不值一提的小东西,才发现自己OUT了,为此博主将#define的使用方法总结了一下,如下所示:(如有不足请批评指正)

    1. 最最最简单的define定义
        不赘述了,说一下其他的吧,如#define MAX 10,编译器在处理这个代码之前会对MAX进行处理,替换为10,或许有些人认为这样的定义看起来和const常量很相似,但是他们还是有区别的,#define的定义其实就是简单的文本的替换,并不是作为一个量来使用

    2. 用#define来对函数进行“定义”
        很多就会问了,什么?居然还能用#define来定义函数,坑爹么?其实咋说呢,就是类似的一个函数定义罢了,和真正的函数定义当然还是有区别的了,下面进行举例说明:

       还是用上面的MAX的例子:#define MAX(a,b) ((a) > (b) ? (a) : (b)),这个定义就返回两个数中较大的那个,不知道你们看到了没看到,这个”函数“没有类型检查,像不像函数模板?像?不像?
        其实是有点像的,可以作为一个普通的模板来使用罢了,他肯定没函数模板那么安全,WHY?看下面的例子:
        
        #define MINUS(a,b) a - b,眨眼一看,这个肯定是减法操作的define,有木有?对,没错,就是这个意思,这个定义在一般的使用中没问题,但是在特定的情况下使用会出现问题,如果我们要这样去使用     的话,展开之后会是什么样子呢?如:2 * MINUS(a,b) / 4,就像我前面所说的那样,宏其实就是一个简单的文本替换,所以展开时候就变为 2 * a - b / 4,和我们想要的结果是不是不一样?是不是错         了?有木有?那要如何解决这个问题呢,很简单,给原定义加一个括号就OK了,也就是#define MINUS(a,b) (a - b)

        再说一个经常出现的一个错误,看下面的例子:
        #define pin (int *)
        pin a,b;
        本意其实都想让a和b成为int型指针,但是实际上却变成了int *a,b;a是int型指针,b是int型变量,咋处理捏?这个时候typedef就出来了,它说我可以满     足define满足不了的要求,所以改成
        typedef pin (int *) 就OK了。
        
        TIP:我们在写code的时候一定要养成一个良好的习惯和一个良好的代码编写风格,建议所有的层次都加上括号

    3. define的单行定义,举例说明之,属于少见用法
        #define A(x) ##x
        #define B(x) #@x
        #define C(x) #x
        如果我们假设x=1,那么A(1)就是1,B(1)就是‘1’,C(1)就是”1“

    4. define的多行定义
        #define可以进行多行定义,虽然看起来有点蛋疼,但是确实是一个灰常经典而且在设备驱动代码中经常要用到的一个方法,格式如下:
        #define MACRO(arg1,arg2) do {  \
        test1; \
        test2; \
        }while(0)
        
        TIP:在每一行的末尾要加上\,切记!

    5. 定义宏和取消宏定义的方法
        定义一个宏使用#define,取消一个宏定义使用#undef

    6. 使用宏进行条件编译
        格式如下:#ifdef ... (#else) ... #endif
        如:
        #ifdef HELLO
        #define WORLD 1
        #else
        #define WORLD 0
        #endif

    7. 用define来处理头文件被头文件或者源文件包含的情况
        由于头文件包含可以嵌套,那么c文件有可能包含多次同一个头文件,就会出现重复定义的问题的,那么可以就通过条件编译开关来避免重复包含,如下:
        #ifndef _HELLO_H_
        #define _HELLO_H_
        ...
        //文件内容
        ...
        #endif

    展开全文
  • c语言中#define用法C语言中,可以用 #define 定义一个标识符来表示一个常量。其特点是:定义的标识符不占内存,只是一个临时的符号,预编译后这个符号就不存在了。预编译又叫预处理。预编译不是编译,而是编译前的...

    75e80326ddc7f3be35b47f6f8de2f444.png

    c语言中#define的用法

    C语言中,可以用 #define 定义一个标识符来表示一个常量。其特点是:定义的标识符不占内存,只是一个临时的符号,预编译后这个符号就不存在了。

    预编译又叫预处理。预编译不是编译,而是编译前的处理。这个操作是在正式编译之前由系统自动完成的。

    #define的格式为:#define 标识符 常量

    推荐学习:c语言视频教程

    为了将标识符与变量名区别开来,习惯上标识符全部用大写字母表示。宏定义用得最多的地方是在数组中用于指定数组的长度。

    下面来写一个程序:# include

    # define NUM 5

    int main(void)

    {

    int i, j = NUM;

    int a[NUM] = {0};

    printf("请输入%d个数:", j);

    for (i=0; i

    {

    scanf("%d", &a[i] );

    }

    for (i=0; i

    {

    printf("%dx20", a[i]);

    }

    printf("

    ");

    return 0;

    }

    输出结果是:请输入5个数:5 4 3 2 1

    5 4 3 2 1

    NUM 是定义的宏,它表示的是其后的常量(而不是变量)。此外,程序中用双引号括起来的宏在预处理的时候是不会被宏替换的。因为在 C 语言中,用双引号括起来表示的是字符串。

    更多C语言教程,请关注PHP中文网!

    展开全文
  • 以下是烟花美文网小编分享给大家的C语言#define用法,欢迎阅读!#define用法#define 是一个预处理指令,这个预处理执行可以定义宏。与所有预处理指令一样,预处理指令#define用#符号作为行的开头。预处理指令从#...

    【www.okfie.com--英语阅读】

    引导语:预处理器是在真正的编译开始之前由编译器调用的独立程序。以下是烟花美文网小编分享给大家的C语言#define的用法,欢迎阅读!

    #define的用法

    #define 是一个预处理指令,这个预处理执行可以定义宏。与所有预处理指令一样,预处理指令#define用#符号作为行的开头。预处理指令从#开始,到其后第一个换行符为止。也就是说,指令的长度限于一行代码。如果想把指令扩展到几个物理行,可使用反斜线后紧跟换行符的方法实现,该出的换行符代表按下回车键在源代码文件中新起一行所产生的字符,而不是符号 \n 代表的字符。在预处理开始钱,系统会删除反斜线和换行符的组合,从而达到把指令扩展到几个物理行的效果。可以使用标准C注释方法在#define行中进行注释。

    //使用反斜线+回车

    #define OW "hello\

    world!" /*注意第二行要左对齐*/

    每一个#define行由三部分组成:

    第一部分,指令#deine自身。

    第二部分,所选择的缩略语,这些缩略语称为宏(分为对象宏和函数宏)。宏的名字中不允许有空格,而且必须遵循C变量命名规则:只能使用字母、数字和下划线(_),第一个字符不能为数字。习惯上宏名用大写字母表示,以便于与变量区别。但也允许用小写字母。

    第三部分,(#define行的其余部分)称为替换列表或主体。

    注意,结尾没有分号

    下面来看一个例子:

    #include

    #define OW 2 * 2

    #define OW 2 * 2

    //#undef OW 需要先取消宏定义

    #define OW 2*2

    int main (void)

    {

    printf ("%d\n", OW);

    return 0;

    }

    输出结果:

    define.c:5:0: 警告: “OW”重定义 [默认启用]

    define.c:4:0: 附注: 这是先前定义的位置

    相同定义意味着主体具有相同顺序的语言符号。因此,下面两个定义相同:

    #define OW 2 * 2

    #define OW 2 * 2

    两者都有三个相同的语言符号,而且额外的空格不是主体的一部分。下面的定义则被认为是不同的:

    #define OW 2*2

    上式只有一个(而非三个)语言符号,因此与前面两个定义不同。可以使用#undef指令重新定义宏。

    宏所代表的数字可以在编译命令中指定(使用-D选项)

    /*

    宏演示

    */

    #include

    int main()

    {

    int num=0;

    int arr[SIZE]={}; //使用gcc -D可以宏定义这个数字

    for(num = 0;num <= SIZE - 1;num++)

    {

    arr[num]=num;

    printf("%d ",arr[num]);

    }

    printf("\n");

    return 0;

    }

    gcc -DSIZE=4 define.c

    输出结果:

    0 1 2 3

    函数宏:

    通过使用参数,可以创建外形和作用都与函数相似的类函数宏。宏的参数也用圆括号括起来。类函数宏的定义中,用圆括号括起来一个或多个参数,随后这些参数出现在替换部分。

    #include

    #define SQUARE(X) X*X

    #define PR(X) printf ("The result is %d\n", X)

    int main (void)

    {

    int x = 4;

    int z;

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

    z = SQUARE(x);

    printf ("Evaluating SQUARE(x): ");

    PR(z);

    z = SQUARE(2);

    printf ("Evaluating SQUARE(2): ");

    PR(z);

    printf ("Evaluating 100/SQUARE(2): ");

    PR(100/SQUARE(2));

    z = SQUARE(x+2);

    printf ("Evaluating SQUARE(x+2): ");

    PR(z);

    printf ("x is %d\n", x);

    z = SQUARE(++x);

    printf ("Eavluating SQUARE(++x): ");

    PR(SQUARE (++x));

    printf ("After incrementing, x is %x\n", x);

    return 0;

    }

    输出结果:

    x = 4

    Evaluating SQUARE(x): The result is 16

    Evaluating SQUARE(2): The result is 4

    Evaluating 100/SQUARE(2): The result is 100

    Evaluating SQUARE(x+2): The result is 14

    x is 4

    Eavluating SQUARE(++x): The result is 36

    After incrementing, x is 6

    SQUARE(x+2) 输出结果是14,而不是想要的6*6 = 36。这是因为预处理器不进行计算,而只进行字符串替换。在出现x的地方,预处理都用字符串 x+2进行替换。x*x 变为 x+2*x+2 根据运算符优先级,则结果为 14

    100/SQUARE(2)输出结果是 100,而不是想要的 25。因为,根据优先级规则,表达式是从左到右求值的。

    100/2*2 = 100

    要处理前面两个示例中的情况,需要如下定义:

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

    从中得到的经验是使用必须的足够多的圆括号来保证以正确的顺序进行运行和结合。

    SQUARE(++x) 根据编译器的不同会出现两种不同的结果。解决这个问题的最简单的方法是避免在宏的参数中使用++x。一般来说,在宏中不要使用增量或减量运算符。

    参看:C 语言再学习 -- 运算符与表达式

    利用宏参数创建字符串:#运算符

    在类函数宏的替换部分中,#符号用作一个预处理运算符,它可以把语言符号转化为字符串。

    展开全文
  • #define中使用参数可以创建外形和作用与函数类似的类函数宏。...C语言#define中使用参数Parts of a function-like macro definition下面是一个类函数宏的示例:#define SQUARE(X) X*X程序可以...

    在#define中使用参数可以创建外形和作用与函数类似的类函数宏。带有参数的宏看上去很像函数,因为这样的宏也使用圆括号。类函数宏定义的圆括号中可以有一个或多个参数,随后这些参数出现在替换体中,如下图所示。

    C语言之在#define中使用参数

    Parts of a function-like macro definition

    下面是一个类函数宏的示例:

    #define SQUARE(X) X*X

    在程序中可以这样用:

    z = SQUARE(2);

    这看上去像函数调用,但是它的行为和函数调用完全不同。程序macarg.c 演示了类函数宏和另一个宏的用法。该示例中有一些陷阱,请读者仔细阅读序。

    The macarg.c Program

    /mac_arg.c -- macros with arguments/

    #include

    #define SQUARE(X) X*X

    #define PR(X) printf("The result is %d.n", X)

    int main(void)

    {

    int x = 5;

    int z;

    printf("x = %dn", x);

    z = SQUARE(x);

    printf("Evaluating SQUARE(x): ");

    PR(z);

    z = SQUARE(2);

    printf("Evaluating SQUARE(2): ");

    PR(z);

    printf("Evaluating SQUARE(x+2): ");

    PR(SQUARE(x+2));

    printf("Evaluating 100/SQUARE(2): ");

    PR(100/SQUARE(2));

    printf("x is %d.n", x);

    printf("Evaluating SQUARE(++x): ");

    PR(SQUARE(++x));

    printf("After incrementing, x is %x.n", x);

    return 0;

    }

    SQUARE宏的定义如下:

    #define SQUARE(X) XX

    这里,SQUARE是宏标识符,SQUARE(X)中的X是宏参数,XX是替换列表。程序清单16.2中出现SQUARE(X)的地方都会被XX替换。这与前面的示例不同,使用该宏时,既可以用X,也可以用其他符号。宏定义中的X由宏调用中的符号代替。因此,SQUARE(2)替换为22,X实际上起到参数的作用。 然而,稍后你将看到,宏参数与函数参数不完全相同。下面是程序的输出。注意有些内容可能与我们的预期不符。实际上,你的编译器输出甚至与下面的结果完全不同。

    x = 5 Evaluating SQUARE(x): The result is 25. Evaluating SQUARE(2): The result is 4. Evaluating SQUARE(x+2): The result is 17. Evaluating 100/SQUARE(2): The result is 100. x is 5. Evaluating SQUARE(++x): The result is 42. After incrementing, x is 7.

    前两行与预期相符,但是接下来的结果有点奇怪。程序中设置x的值为5,你可能认为SQUARE(x+2)应该是77,即49。但是,输出的结果是17,这不是一个平方值!导致这样结果的原因是,我们前面提到过,预处理器不做计算、不求值,只替换字符序列。预处理器把出现x的地方都替换成x+2。因此,xx变成了x+2x+2。如果x为5,那么该表达式的值为: xx 变成了 x+2*x+2。

    如果x为5,那么该表达式的值为:

    5+2*5+2 = 5 + 10 + 2 = 17

    该例演示了函数调用和宏调用的重要区别。函数调用在程序运行时把参数的值传递给函数。宏调用在编译之前把参数记号传递给程序。这两个不同的过程发生在不同时期。是否可以修改宏定义让SQUARE(x+2)得36?当然可以,要多加几个圆括号:

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

    现在SQUARE(x+2)变成了(x+2)(x+2),在替换字符串中使用圆括号就得到符合预期的乘法运算。但是,这并未解决所有的问题。下面的输出行:

    100/SQUARE(2)

    将变成:

    100/22

    根据优先级规则,从左往右对表达式求值:(100/2)2,即50*2,得100。把SQUARE(x)定义为下面的形式可以解决这种混乱:

    #define SQUARE(x) (xx)

    这样修改定义后得100/(22),即100/4,得25。要处理前面的两种情况,要这样定义:

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

    因此,必要时要使用足够多的圆括号来确保运算和结合的正确顺序。尽管如此,这样做还是无法避免程序中最后一种情况的问题。SQUARE(++x)变成了++x++x,递增了两次x,一次在乘法运算之前,一次在乘法运算之后:

    SQUARE(++x)

    变成了:

    ++x*++x

    递增了两次x,一次在乘法运算之前,一次在乘法运算之后:

    ++x++x = 67 = 42

    由于标准并未对这类运算规定顺序,所以有些编译器得76。而有些编译器可能在乘法运算之前已经递增了x,所以77得49。在C标准中,对该表达式求值的这种情况称为未定义行为。无论哪种情况,x的开始值都是5,虽然从代码上看只递增了一次,但是x的最终值是7。解决这个问题最简单的方法是,避免用++x作为宏参数。一般而言,不要在宏中使用递增或递减运算符。但是,++x可作为函数参数,因为编译器会对++x求值得5后,再把5传递给函数。

    1 用宏参数创建字符串:#运算符

    下面是一个类函数宏:

    #define PSQR(X) printf("The square of X is %d.n", ((X)*(X)));

    假设这样使用宏:

    PSQR(8);

    输出为:

    The square of X is 64.

    注意双引号字符串中的X被视为普通文本,而不是一个可被替换的记号。C允许在字符串中包含宏参数。在类函数宏的替换体中,#号作为一个预处理运算符,可以把记号转换成字符串。例如,如果x是一个宏形参,那么#x就是转换为字符串"x"的形参名。这个过程称为字符串化(stringizing)。程序清单16.3演示了该过程的用法。

    Listing 16.3 The subst.c Program

    /subst.c -- substitute in string/

    #include

    #define PSQR(x) printf("The square of " #x " is %d.n",((x)*(x)))

    int main(void)

    {

    int y = 5;

    PSQR(y);

    PSQR(2 + 4);

    return 0;

    }

    该程序的输出如下:

    The square of y is 25. The square of 2 + 4 is 36.

    调用第1个宏时,用"y"替换#x。调用第2个宏时,用"2+4"替换#x。ANSI C字符串的串联特性将这些字符串与printf()语句的其他字符串组合,生成最终的字符串。例如,第1次调用变成:

    printf("The square of " "y" " is %d.n",((y)*(y)));

    然后,字符串串联功能将这3个相邻的字符串组合成一个字符串:

    "The square of y is %d.\n"

    2 预处理器黏合剂:##运算符

    与#运算符类似,##运算符可用于类函数宏的替换部分。而且,##还可用于对象宏的替换部分。##运算符把两个记号组合成一个记号。例如,可以这样做:

    #define XNAME(n) x ## n

    然后,宏XNAME(4)将展开为x4。程序清单16.4演示了##作为记号粘合剂的用法。

    Listing 16.4 The glue.c Program

    // glue.c -- use the ## operator

    #include

    #define XNAME(n) x ## n

    #define PRINT_XN(n) printf("x" #n " = %dn", x ## n);

    int main(void)

    {

    int XNAME(1) = 14; // becomes int x1 = 14;

    int XNAME(2) = 20; // becomes int x2 = 20;

    int x3 = 30;

    PRINT_XN(1); // becomes printf("x1 = %dn", x1);

    PRINT_XN(2); // becomes printf("x2 = %dn", x2);

    PRINT_XN(3); // becomes printf("x3 = %dn", x3);

    return 0;

    }

    该程序的输出如下:

    x1 = 14

    x2 = 20

    x3 = 30

    注意,PRINTXN()宏用#运算符组合字符串,##运算符把记号组合为一个新的标识符。

    3 变参宏:…和VAARGS

    一些函数(如printf())接受数量可变的参数。stdvar.h头文件(本章后面介绍)提供了工具,让用户自定义带可变参数的函数。C99/C11也对宏提供了这样的工具。虽然标准中未使用“可变”(variadic)这个词,但是它已成为描述这种工具的通用词(虽然,C标准的索引添加了字符串化(stringizing)词条,但是,标准并未把固定参数的函数或宏称为固定函数和不变宏)。通过把宏参数列表中最后的参数写成省略号(即,3个点…)来实现这一功能。这样,预定义宏 _ VAARGS 可用在替换部分中,表明省略号代表什么。例如,下面的定义:

    #define PR(...) printf(__VA_ARGS__)

    假设稍后调用该宏:

    PR("Howdy");

    PR("weight = %d, shipping = $%.2fn", wt, sp);

    对于第1次调用,_ VAARGS 展开为1个参数:"Howdy"。对于第2次调用, VAARGS 展开为3个参数:

    "weight = %d, shipping = $%.2fn", wt, sp

    因此,展开后的代码是:

    printf("Howdy");

    printf("weight = %d, shipping = $%.2fn", wt, sp);

    程序variadic.c演示了一个示例,该程序使用了字符串的串联功能和#运算符。

    // variadic.c -- variadic macros

    #include

    #include

    #define PR(X, ...) printf("Message " #X ": " __VA_ARGS__)

    int main(void)

    {

    double x = 48;

    double y;

    y = sqrt(x);

    PR(1, "x = %gn", x);

    PR(2, "x = %.2f, y = %.4fn", x, y);

    return 0;

    }

    第1个宏调用,X的值是1,所以#X变成"1"。展开后成为:

    print("Message " "1" ": " "x = %gn", x);

    然后,串联4个字符,把调用简化为:

    print("Message 1: x = %gn", x);

    下面是该程序的输出:

    Message 1: x = 48

    Message 2: x = 48.00, y = 6.9282

    记住,省略号只能代替最后的宏参数:

    #define WRONG(X, ..., Y) #X #__VA_ARGS__ #y // won't work

    展开全文
  • 学习了这么多年C语言,说实话对宏自以为了如指掌了,没想到看内核代码的时候还是那么吃力,设备驱动代码有很多这样或者那样的宏定义,各种define,博主学习的过程中将C语言中所出现的#define定义整理总结了一下...
  • C语言define用法

    千次阅读 2020-12-23 22:38:01
    C语言中define用于预定义,只是起替换作用。 1.定义数,例如,#define PI 3.14用于兀的处理,main函数调用时将PI替换成3.14,不会进行检查。 2.定义字符串,没错,是字符串,不是字符数组,例如,#define STR “ABC...
  • C语言中define用法

    2014-02-22 17:08:27
    C语言中define用法 defineC语言中的预处理命令,它用于宏定义,可以提高源代码的可读性,为编程提供方便。 预处理命令以“#”号开头,如包含命令#include,宏定义命令#define等。一般都放在...
  • C语言中#define使用方法
  • 有的时候为了程序的通用性,可以使用define预处理宏定义命令,它的具体作用就是方便程序段的定义和修改,下面就来详解C语言中的#define宏定义命令用法.
  • C语言中#define用法

    2016-03-18 13:01:41
    C语言中#define用法
  • C语言中ifndef,define ,endif的用法 语句1 #ifndef 标识 1 语句2 #define 标识 2 语句3 #endif 语句4 语句5 …… 如果标识1没有被定义,则重新定义标识1,执行语句2,3,4,5,…… 如果标识1已经被定义,...
  • 单片机C语言知识用法之#define

    千次阅读 2018-02-10 22:19:29
    #define的定义:#defineC语言中的一个预处理指令,其中的“#”表示这是一条预处理命令·。凡是以“#”开头的均为预处理命令,“define”为宏定义命令,“标识符”为所定义的宏名。#define TIME_NUM 1000 //定义...
  • 1、宏定义的一般形式为: 宏定义: #define 标识符 常量 //注意:没有分号...使用宏定义代替一个程序常用的变量,当需要修改该变量时,只需修改其宏定义即可,方便代码的修改和维护。 2.2 提高代码的可读性。 3、程序
  • defineC语言中的预处理命令,它用于宏定义,可以提高源代码的可读性,为编程提供方便。 预处理命令以“#”号开头,如包含命令#include,宏定义命令#define等。一般都放在源文件的前面,它们称为预处理部分。 ...
  • C语言中#define用法总结

    万次阅读 多人点赞 2018-04-09 16:49:52
    1.简单的宏定义#define 标识符 替换列表(替换列表可以是数,字符串字面量,标点符号,运算符,标识符,关键字,字符常量。注意:替换列表是可以为空的)典型错误:#define N = 100int a[N]; /*这样会成为int a[= ...
  • 其实这个是困惑了我好久的问题,没想到上机课做到的题里找到了答案——我的困惑是:#define与const到底有什么区别。题目: 代码如下 复制代码 #define N 2#define M N 1#define NUM 2*M 1main( ){ int i;for(i=1;i...
  • C语言中预处理命令#define用法 defineC语言中的预处理命令,它用于宏定义,可以提高源代码的可读性,为编程提供方便。 预处理命令以“#”号开头,如包含命令#include,宏定义命令#define等。一般都放在源文件的...
  • #define NAME "GIGATHINK, INC." #define ADDRESS "101 Megabuck Plaza" #define PLACE "Megapolis, CA 94904" #define WIDTH 40 void starbar(void); int main() {  printf("%s\n",NAME);  

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 93,647
精华内容 37,458
关键字:

define在c语言中的用法

c语言 订阅