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语言学习之路————预处理2.0 -> 正文阅读

[C++知识库]c语言学习之路————预处理2.0

? 1.带副作用的宏参数

? ?如果宏的参数中带有改变传过来的参数,形式比如说自增、自减,它可能带有副作用exp:

#define MAX(x,y) ((x>y)?(x):(y))
int main()
{
	int a = 10;
	int b = 20;
	printf("%d\n", MAX(a++, b++));//21
	//printf("%d",(a++>b++)?(a++):(b++));
	//这里比较完之后a,b都自增了,输出的较大值b会是21,在输出之后b又自增
	printf("%d\n", a);//11
	//a在上面的式子中只自增了一次变成11
	printf("%d\n", b);//22
	//而b自增了两次,一次在比较之后,一次在输出之后,所以b现在等于22
	return 0;
}

?2.宏和函数的对比

函数的参数需要特定的参数,而宏在传参的时候不需要考虑数据类型,它只是进行替换;但在程序序调试的时候,宏出现的错误不容易被找出;函数在调用和传参还有返回需要大量的汇编代码,花费的时间可能更长,而宏在预处理阶段就发生了替换;但是在每次宏的替换都会将一段代码插入到代码中,而函数仅有一段代码,每次使用的时候仅需调用;函数参数是不能传数据类型的,而宏可以;

#define MALLOC(num,type) (type*)malloc(num*sizeof(type))
#define SIZEOF(type) sizeof(type)
void put_data(int* pr)
{
	int i = 0;
    //动态连续空间放入数据
	for (i = 0; i < 10; i++)
	{
		pr[i] = i;
		
	}
    //打印
	for (i=0; i <10; i++)
	{
		printf("%d ", pr[i]);
	}
	printf("\n");
}
int main()
{
    //宏传类型参数,可行
	printf("%d\n", SIZEOF(int));//4

	//动态开辟空间
	int* ptr1 = (int*)malloc(10 * sizeof(int));
	put_data(ptr1);//0 1 2 3 4 5 6 7 8 9
	
	int* ptr = MALLOC(10, int);
	put_data(ptr);//0 1 2 3 4 5 6 7 8 9
    //释放空间
	free(ptr1);
	ptr1 = NULL;
	free(ptr);
	ptr = NULL;
	return 0;
}

?#undef用于取消符号定义的

#define MAX(x,y) ((x>y)?(x):(y))
int main()
{
	int a = 20;
	int b = 30;
	printf("%d", MAX(a, b));
#undef MAX(x,y)
	printf("%d", MAX(a, b));//error 未定义标识符
	return 0;
}

? 3.命令行定义

gcc test.c -D SZ=10在程序运行之前就定义好,

4.条件编译

在一段程序中,也许可以遇见我们只在特定情况下需要的代码,或者只需要使用一次的代码,我们可以通过条件编译,进行判断选择这段代码需不需要编译

#define PRINT_S
int main()
{
	int a = 20;
	int b = 0;
#ifdef PRINT//这里的就是说之前定义过PRINT这个符号,程序就会编译这段代码,反之就会跳过
	printf("%d", a);//注意如果一段代码不会进行编译,就是灰色的(vs2017下)
#endif//这里的endif是条件编译的结束语句,与ifdef搭配
#ifdef PRINT_S
	printf("%d", a);//20
#endif
	//1.#if 常量表达式
#if 1 //为真进行编译
	printf("%d", a);//20
#endif
	//2.多分支判断
#if 20>30 //为假不进行编译
	printf("%d", a);
#elif 20==30
	printf("%d", a);
#else 
	printf("%d", a);//20
#endif
	//3.#if defined(符号)
#if defined(PRINT_S)//如果定义过
	printf("%d", a);//20
#endif
#if !defined(PRINT_S)//如果没有定义过(但定义过)
	printf("%d", a);//20
#endif
	//4.
	return 0;
}

5.文件包含

在头文件包含的过程,是将头文件的内容copy一份到现在.c程序中进行编译,在我们实际写工程的过程中,其实会有意无意的将一个头文件包含多次,那么整个项目当中的就会有很多的代码冗余,在我们的库函数有解决办法

//假设这是我们要包含的头文件,我们一般会采取以下方式,防止一个头文件被多次包含
#ifndef __PASS__
#define __PASS__
//这里面是头文件的内容
//.......
#endif
//这样头文件的内容只能被包含一次(编译)

//当然还有其他的解决办法(现在多采用)
#pragma once
//这里面是头文件的内容
//.......

? 其他的预处理指令:#error(如果在编译程序的过程中遇到,会编译一个错误提示信息,并停止编译)、#pragma(指定一个跟踪选择)、#line(改变当前命令行数和文件名称)等? ? ? ? ? ? ? ? ? ?

6.宏offsetof可以查偏移? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

#include <stddef.h>
struct S
{
	//默认对齐数为8
	int a;//4 占用了偏移量为0 1 2 3的地址共四个字节
	char b;//1 占用了偏移量为4的地址 共一个字节
	double c;//8 现在接下来使用的的空间地址的偏移量为5,但5不是八的倍数,所以要将指针移到偏移量为8的地址继续接下来的的存储,
	//前面浪费了3个字节的空间,再将c存进去,占8个字节
}s;
//这个结构体的大小为16  为最大对齐数的倍数
#define OFFSETOF(struct_typename,member_name) (int)&(((struct_typename*)0)->member_name)
                                               //解释:我们将结构体的开始放成员的地址为0(结 
                                              //构体类型的地址或者指针)当首地址为0,
                                               //那对应偏移量的成员的地址就等于偏移量,exp: 
                                               //上面b的地址就是偏移量4,最后的类型强转
                                               //的强制类型转化,将地址的转换为整型,地址是十 
                                               //六进制数字,而如果指针变量为整型常量,指针的
                                               //存放的地址将会被赋值为这个整型常量(((struct 
                                               //S*)0)->a)的地址为  0X00000000,在这个地址偏 
                                               //移4之后放下b,而此时b的地址为0x00000004,对 
                                               //这些地址强转成整型,就会得到0,4,8等成员的 
                                               //相较首地址的偏移量
int main()
{
	//printf("%d\n", sizeof(s));//16
    //使用c库里定义的宏
	//printf("a在结构体中的偏移量%d\n", offsetof(struct S,a));//0
	//printf("b在结构体中的偏移量%d\n", offsetof(struct S, b));//4
	//printf("c在结构体中的偏移量%d\n", offsetof(struct S, c));//8
 
    //使用上面自己定义的宏
	printf("a在结构体中的偏移量%d\n", OFFSETOF(struct S, a));//0
	printf("b在结构体中的偏移量%d\n", OFFSETOF(struct S, b));//4
	printf("c在结构体中的偏移量%d\n", OFFSETOF(struct S, c));//8

	return 0;
}

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-10-25 12:21:44  更:2021-10-25 12:23:50 
 
开发: 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/24 5:35:44-

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