C语言 宏

C语言中我们可以通过宏来定义常量表达式。定义常量时与const有何差别?定义表达式时与函数有何差别呢?

C语言中通过#define来定义宏:

  • #define预处理器处理的单元实体之一
  • #define定义的宏可以出现在程序的任意位置
  • #define定义之后的代码都可以使用这个宏

定义宏常量

#define定义的宏常量可以直接使用。

#define定义的宏常量本质为字面量。字面量不占用内存空间。

宏常量定义分析

下面的宏常量定义正确吗?

#define ERROR -1
#define PATH1 "D:\test\test.c"
#define PATH2 D:\test\test.c
#define PATH3 D:\test\
test.c

int main()
{
    int err = ERROR;
    char* p1 = PATH1;
    char* p2 = PATH2;
    char* p3 = PATH3;
}

我们进行单步编译,进行预处理编译:

gcc -E deepinout.com.c -o deepinout.com.i

结果为:

C语言宏的使用

再进行完整的编译:

C语言宏的使用

定义宏表达式

C语言通过宏定义表达式

  • #define表达式的使用类似函数调用
  • #define表达式可以比函数更强大
  • #define表达式比函数更容易出错

宏表达式分析示例

#include <stdio.h>

#define _SUM_(a, b) (a) + (b)
#define _MIN_(a, b) ((a) < (b) ? (a) : (b))
#define _DIM_(a) sizeof(a)/sizeof(*a)


int main()
{
    int a = 1;
    int b = 2;
    int c[4] = {0};

    int s1 = _SUM_(a, b); // (a) + (b)
    int s2 = _SUM_(a, b) * _SUM_(a, b); // (a) + (b)*(a) + (b)
    int m = _MIN_(a++, b); //  ((a++) < (b) ? (a++) : (b))
    int d = _DIM_(c); // sizeof (a) / sizeof(*a)

    printf("s1 = %d\n", s1);
    printf("s2 = %d\n", s2);
    printf("m = %d\n", m);
    printf("d = %d\n", d);

    return 0;
}

#define _DIM_(a) sizeof(a)/sizeof(*a) 是宏比函数强大的地方,C语言里面无法通过一个函数来计算数组的大小。

输出结果:

C语言宏的使用

宏表达式与函数对比

宏表达式与函数的对比:

  • 宏表达式被预处理器处理,编译器不知道宏表达式的存在
  • 宏表达式用“实参”完全替代形参,不进行任何运算
  • 宏表达式没任何的“调用”开销
  • 宏表达式中不能出现递归定义,下面这个定义会报错
    • #define _SUM_(n) ((n > 0) ? (_SUM_(n-1)) : 0)

宏作用域分析

下面的示例说明宏定义的常量或表达式是否有作用域限制。

// #include <stdio.h>

void def()
{
    #define PI 3.1415926
    #define AREA(r) r * r * PI
}

double area(double r)
{
    return AREA(r);
}

int main()
{
    double r = area(5);

    // printf("PI = %f\n", PI);
    // printf("d = 5; a = %f\n", r);

    return 0;
}

预编译结果:

gcc -E deepinout.com.c -o deepinout.com.i

C语言宏的使用

打开注释编译运行结果:

C语言宏的使用

C语言的内置宏

C语言内置了一些宏,常用的如下表所示

C语言内置宏

宏使用综合示例

#include <stdio.h>
#include <malloc.h>

#define MALLOC(type, x) (type*)malloc(sizeof(type)*x)

#define FREE(p) (free(p), p=NULL)

#define LOG(s) printf("[%s] {%s:%d} %s \n", __DATE__, __FILE__, __LINE__, s)

#define FOREACH(i, m) for(i=0; i<m; i++)
#define BEGIN {
#define END   }

int main()
{
    int x = 0;
    int* p = MALLOC(int, 5);

    LOG("Begin to run main code...");

    FOREACH(x, 5)
    BEGIN
        p[x] = x;
    END

    FOREACH(x, 5)
    BEGIN
        printf("%d\n", p[x]);
    END

    FREE(p);

    LOG("End");

    return 0;
}

输出结果:

C语言宏的使用

总结

  • 预处理器直接对宏进行文本替换
  • 宏使用时的参数不会进行求值和运算
  • 预处理器不会对宏定义进行语法检查
  • 宏定义时出现的语法错误只能被编译器检测
  • 宏定义的效率高于函数调用
  • 宏的使用会带来一定的副作用

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程

C语言教程