0


【C语言】程序环境和预处理|预处理详解|定义宏(下)

主页:114514的代码大冒

qq:2188956112(欢迎小伙伴呀hi✿(。◕ᴗ◕。)✿ )

Gitee:庄嘉豪 (zhuang-jiahaoxxx) - Gitee.com

文章目录


前言

咱们书接上回


2.5带副作用的宏参数

先来看一段代码

#define MAX(x,y) ((x)>(y)?(x):(y))

int main()
{
    int a = 4;
    int b = 6;
    int m = MAX(a++, b++);
    printf("%d\n", m); 
    printf("a=%d b=%d\n", a, b);

    return 0;
}

这个结果是什么呢?

为什么?

我们一样要考上文中的“宏是一种替换”的概念,先做一下替换然后我们来解析一下

当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能出现危险,导致不可预测的后果。副作用就是表达式求值的时候出现的永久性效果。

x+1;//不带副作用
x++;//带有副作用

但是在这里这种情况,函数就不会发生类似问题

这里我提供了测试代码,读者可自取


#define MAX(x,y) ((x)>(y)?(x):(y))

int Max(int x, int y)
{
    return x > y ? x : y;

}

int main()
{
    //int m = MAX(2, 3);
    //printf("%d\n", m);
    int a = 4;
    int b = 6;
    int m = MAX(a++, b++);
    //int m = Max(a++, b++);
    printf("%d\n", m); 
    // m = 7
    printf("a=%d b=%d\n", a, b);
    

    return 0;
}

2.6宏和函数的对比

函数的反汇编

宏的反汇编

宏明显要快不少嘛

宏通常被应用于执行简单的运算。

比如在两个数中找出较大的一个。

宏的优点:

  1. 用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。

所以宏比函数在程序的规模和速度方面更胜一筹

  1. 更为重要的是函数的参数必须声明为特定的类型。

所以函数只能在类型合适的表达式上使用。反之这个宏怎可以适用于整形、长整型、浮点型等可以用于>来比较的类型。

宏是类型无关的

宏的缺点

当然和函数相比宏也有劣势的地方:

  1. 每次使用宏的时候,一份宏定义的代码将插入到程序中。除非宏比较短,否则可能大幅度增加程序的长度。

  2. 宏是没法调试的。

  3. 宏由于类型无关,也就不够严谨。

  4. 宏可能会带来运算符优先级的问题,导致程容易出现错。

宏没有类型,如上图所示,函数只能进行固定类型数据的操作,而宏却可以忽视这一细节

但是对应的,宏是一种替换,也就是说,他会把定义的内容替换到正文代码中,造成代码超度变长

另外就是像上文所说的那种“副作用”,足以看出宏在调试时的问题是比较大的,

因为“你看到的并非你看到的(宏替换的关系)”

所以总的说来,宏有着优点也有着缺点

具体使用函数还是宏,要根据实际情况


**属 **

**性 **

**#define****定义宏 **

函数

每次使用时,宏代码都会被插入到程序中。除了非常

小的宏之外,程序的长度会大幅度增长

函数代码只出现于一个地方;每

次使用这个函数时,都调用那个

地方的同一份代码

更快

存在函数的调用和返回的额外开 销,所以相对慢一些

宏参数的求值是在所有周围表达式的上下文环境里,

除非加上括号,否则邻近操作符的优先级可能会产生

不可预料的后果,所以建议宏在书写的时候多些括

号。

函数参数只在函数调用的时候求

值一次,它的结果值传递给函

数。表达式的求值结果更容易预测

参数可能被替换到宏体中的多个位置,所以带有副作 用的参数求值可能会产生不可预料

的结果

函数参数只在传参的时候求值一次,结果更容易控制。

宏的参数与类型无关,只要对参数的操作是合法的, 它就可以使用于任何参数类型。

函数的参数是与类型有关的,如果参数的类型不同,就需要不同的函数,即使他们执行的任务是相同的。

宏是不方便调试的

函数是可以逐语句调试的

宏是不能递归的

函数是可以递归的


**2.7 ****命名约定 **

一般来讲函数的宏的使用语法很相似。所以语言本身没法帮我们区分二者。

那我们平时的一个习惯是:

把宏名全部大写

函数名不要全部大写

3**#undef**

这条指令用于移除一个宏定义。

#undef NAME

//如果现存的一个名字需要被重新定义,那么它的旧名字首先要被移除。

**4 ****命令行定义 **

许多C 的编译器提供了一种能力,允许在命令行中定义符号。用于启动编译过程。

例如:当我们根据同一个源文件要编译出一个程序的不同版本的时候,这个特性有点用处。(假定某个程序中声明了一个某个长度的数组,如果机器内存有限,我们需要一个很小的数组,但是另外一个机器内存大些,我们需要一个数组能够大些。)

#include <stdio.h>
int main()
{
    int array [ARRAY_SIZE];
    int i = 0;
    for(i = 0; i< ARRAY_SIZE; i ++)
   {
        array[i] = i;
   }
    for(i = 0; i< ARRAY_SIZE; i ++)
   {
        printf("%d " ,array[i]);
   }
    printf("\n" );
    return 0;
}

编译指令:

//linux 环境演示
gcc -D ARRAY_SIZE=10 programe.c

5 条件编译

在编译一个程序的时候我们如果要将一条语句(一组语句)编译或者放弃是很方便的。因为我们有条件编译指令。

比如说:

调试性的代码,删除可惜,保留又碍事,所以我们可以选择性的编译

------------------------------条件编译的“条件”不可以是变量------------------------------------------------

因为条件编译中的条件在预处理阶段就已经处理了,而预处理阶段不处理变量

使用方法再举例

关系可以向C语言中的“if.....else”语句考虑

更多例子

6 文件包含

这个多次包含编译器是不会进行报错的,但是这个东西意味着程序将多次调用同一段代码

这显然是多余的,ok,看起来似乎这个多次包含同一文件的错误对于个人来讲很容易规避

但是如果是

下图这般

如何避免呢?

答:条件编译

下面这个放在第一行也具有相同作用

#pragma once//这个也是OK的

#include <filename.h> 和 #include "filename.h"有什么区别?

答:如果使用尖括号,那么程序将直接在系统头文件库寻找该文件

如果使用引号,那么程序将现在本地找一找,找不到才回去系统头文件库查找

从提升效率的角度讲,系统头文件调用时应该使用<>

而个人创建的头文件,应该使用“”


总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。


本文转载自: https://blog.csdn.net/m0_74292919/article/details/129053945
版权归原作者 114514的代码大冒 所有, 如有侵权,请联系我们删除。

“【C语言】程序环境和预处理|预处理详解|定义宏(下)”的评论:

还没有评论