IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C primer plus学习笔记 —— 12、宏定义 -> 正文阅读

[C++知识库]C primer plus学习笔记 —— 12、宏定义


预处理器:在程序运行之前查看程序。
预处理器把符号替换成表示的内容不做表达式计算和求值,就 是简单的转换文本。

#define

预处理器查找一行中以#开始的预处理器指令。指令可以出现在源文件中的任何地方。他的定义从开始一直到源文件末尾都有效。

#include <stdio.h>
#define TWO 2        /* you can use comments if you like   */
#define OW "Consistency is the last refuge of the unimagina\
tive. - Oscar Wilde" /* a backslash continues a definition */
/* to the next line                   */
#define FOUR  TWO*TWO
#define PX printf("X is %d.\n", x)
#define FMT  "X is %d.\n"

int main(void)
{
    int x = TWO;
    
    PX;
    x = FOUR;
    printf(FMT, x);
    printf("%s\n", OW);
    printf("TWO: OW\n");
    
    return 0;
}

注意宏换行时要与上面一行对齐,不然空格也会算进去。

使用宏声明数组

#define LIMIT 20 
const int LIM = 50; 

static int data1[LIMIT];    // 有效
static int data2[LIM];     // 无效 
const int LIM2 = 2 * LIMIT;  // 有效 
const int LIM3 = 2 * LIM;   // 无效

数组的声明可必须是

  1. 整型常量的组合,比如宏定义
  2. 枚举
  3. sizeof表达式
    而const声明的数值不可以。

宏定义的空格

#define EIGHT 4 * 8
#define EIGHT2 4*8

这两个宏定义是不同的,一个是带空格的,而另一个不带空格。空格也是宏定义中的一部分。

重定义

#define LIM 20
#define LIM 20

可以重定义宏,但是重定义的值必须和原值相同。如果不同,则有些编译器会报错,有些会给出警告。

取消定义#undef

在这里插入图片描述
移除LIMIT定义后,就可以给LIMIT重新定义成一个新值。如果没有定义LIMIT,取消定义一样有效。

宏定义中使用参数

看上去像函数调用,但是和函数调用完全不同。
看下面实例

#include <stdio.h>
#define SQUARE(X) X*X
#define PR(X)   printf("The result is %d.\n", X)
int main(void)
{
    int x = 5;
    int z;
    
    z = SQUARE(x); //z = 5*5
    PR(z); //The result is 25.
    z = SQUARE(2); //z = 2*2
    PR(z); //The result is 4.
    PR(SQUARE(x+2)); //z = 5+2*5+2 The result is 17.
    PR(100/SQUARE(2));//PR(100/2*2) The result is 100.
    printf("x is %d.\n", x); // 5
    PR(SQUARE(++x)); //++x*++x = 6*7 The result is 42.
    printf("After incrementing, x is %x.\n", x); //7
    
    return 0;
}

宏参数作为字符串

#define PSQR(x) printf("The square of "#x" is %d.\n",((x)*(x)))
 int main(void)
{
    int y = 5;
    PSQR(y); //The square of y is 25.
    PSQR(2 + 4); //The square of 2 + 4 is 36.
    
    return 0;
}

这里的参数会替换字符串中的"#x"

粘合剂符号##

#include <stdio.h>
#define XNAME(n) x ## n
#define PRINT_XN(n) printf("x"#n" = %d\n", x ## n);

int main(void)
{
    int XNAME(1) = 14;  // int x1 = 14;
    int XNAME(2) = 20;  // int x2 = 20;
    int x3 = 30;
    PRINT_XN(1);        // printf("x1 = %d\n", x1); x1 = 14
    PRINT_XN(2);        // printf("x2 = %d\n", x2); x2 = 20
    PRINT_XN(3);        // printf("x3 = %d\n", x3); x3 = 30
    return 0;
}

可变参数宏 ... _ _VA _ ARGS_ _ 打印

可变参数宏是在宏中printf使用的

#include <stdio.h>
#include <math.h>
#define DEBUG(format, ...)	printf(format, __VA_ARGS__)
 
#define PR(X, ...) printf("Message " #X " : "  __VA_ARGS__)

int main(void)
{
    DEBUG("%s: %d\r\n", "debug", 100); //printf("%s: %d\r\n", "debug", 100)    debug: 100
    double x = 48;
    double y;
    
    y = x*x;
    PR(1, "x = %g\n", x); //Message 1: x = 48
    PR(2, "x = %.2f, y = %.4f\n", x, y); // Message 2: x = 48.00, y = 2304.0000
    
    return 0;
}

宏,函数调用,内联函数

内联函数

把函数变成内联,编译器可能会把函数代码直接替换掉函数调用。
目的:把函数变为内联,目的是尽可能快的调用该函数。

inline int fun(int x)
{
	return x * x;
}
 
int main()
{
	int b = fun(2 + 3);
	return 0;
}

内联会把函数变为下面形式

inline int fun(int x)
{
	return x * x;
}
 
int main()
{
	int b =  (2 + 3) * (2 + 3);
	return 0;
}

未给内联函数预留代码块, 所以无法获得内联函数地址,并且内联函数无法在调试器中显示。
一般我们不在头文件中放可执行代码,但是内联函数是个特例。
内联函数一般是比较简短的函数,我们可以把它写成内联形式。

三者区别

  • 如果调用函数次数比较多:比如二十次,那么如果使用宏,就会产生二十个代码,形成冗余,这时我们使用函数更好,因为只有一个副本节省空间。函数代码量多,功能复杂,体积庞大。这时使用内联则不合适,因为
  • 如果代码功能比较简单,而且函数调用次数少,则可以直接使用宏定义,更直接,简单。

条件宏

#include <stdio.h>
#define JUST_CHECKING //空定义
#define LIMIT 4

int main(void)
{
    int i;
    int total = 0;

    for (i = 1; i <= LIMIT; i++)
    {
        total += 2*i*i + 1;
#ifdef JUST_CHECKING
        printf("i=%d, running total = %d\n", i, total);
#endif
    }
    printf("Grand total = %d\n", total);
    
    return 0;
}

#ifndef主要有两种作用:

  1. 防止某个宏被重复定义,如下代码,如果这个宏没有被定义过,那么我们就定义它。如果定义过就不定义了,这样在多个头文件的时候,就不会有重定义的错误。
#ifndef SIZE
	#define SIZE 100
#endif
  1. 在头文件中使用,防止多次包含同一个文件(最常用的)。当包含头文件很多时,那么我们很可能在不同头文件中都包含了一个头文件,那么如果有些声明比如一些结构类型声明,出现两次就会报错。所以我们就使用下面的方式来防止这种情况。
// names.h --revised with include protection
#ifndef NAMES_H_
#define NAMES_H_

// constants
#define SLEN 32

// structure declarations
struct names_st
{
    char first[SLEN];
    char last[SLEN];
};

// typedefs
typedef struct names_st names;

// function prototypes
void get_names(names *);
void show_names(const names *);
char * s_gets(char * st, int n);

#endif

预定义宏

// predef.c -- predefined identifiers
#include <stdio.h>
void why_me();

int main()
{
    printf("The file is %s.\n", __FILE__);
    printf("The date is %s.\n", __DATE__);
    printf("The time is %s.\n", __TIME__);
    printf("The version is %ld.\n", __STDC_VERSION__);
    printf("This is line %d.\n", __LINE__);
    printf("This function is %s\n", __func__);
    why_me();
    
    return 0;
}

void why_me()
{
    printf("This function is %s\n", __func__);
    printf("This is line %d.\n", __LINE__);
}
// The file is predef.c.
// The date is Oct 29 2022.
// The time is 12:42:30.
// The version is 201710.
// This is line 11.
// This function is main
// This function is why_me
// This is line 21.

#include头文件包含

当预处理器发现#include指令,会把该文件包含到当前文件中,即把include的文件全部内容直接放入当前文件该处。
在这里插入图片描述
双引号,会查找当前工作目录中如果没有再去系统目录中查找。但是查找还是要看编译器,可能会查找当前源文件所在目录,也可能从项目文件所在目录查找。

头文件中存放的东西

在这里插入图片描述
全局变量
在这里插入图片描述

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-10-31 11:35:33  更:2022-10-31 11:37:37 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 5:43:16-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码