条件编译 #和##运算符

news2025/1/13 15:28:34

目录

  • 1. #运算符
  • 2. ##运算符
  • 3. 条件编译
  • 4. 题目分享
  • 总结


正文开始

前言: 本章为C语言语法完结撒花, 下文将进行C语言中#和##操作符以及条件编译的讲解, 来进一步让我们了解C语言.
作者主页: 酷酷学!!!

1. #运算符

#运算符将宏的⼀个参数转换为字符串字⾯量。它仅允许出现在带参数的宏的替换列表中。
#运算符所执⾏的操作可以理解为”字符串化“。

当我们有⼀个变量 int a = 10; 的时候,我们想打印出: the value of a is 10 .
就可以写:

#define PRINT(n) printf("the value of "#n " is %d", n);

当我们按照下⾯的⽅式调⽤的时候:

PRINT(a);//当我们把a替换到宏的体内时,就出现了#a,⽽#a就是转换为"a",时⼀个字符串

代码就会被预处理为:

printf("the value of ""a" " is %d", a);

运⾏代码就能在屏幕上打印:

the value of a is 10

2. ##运算符

##可以把位于它两边的符号合成⼀个符号,它允许宏定义从分离的⽂本⽚段创建标识符。 ## 被称为记号粘合
这样的连接必须产⽣⼀个合法的标识符。否则其结果就是未定义的。

这⾥我们想想,写⼀个函数求2个数的较⼤值的时候,不同的数据类型就得写不同的函数。

int int_max(int x, int y)
{
 return x>y?x:y;
}
float float_max(float x, float y)
{
 return x>y?x:y;
}

但是这样写起来太繁琐了,现在我们这样写代码试试:

//宏定义 
#define GENERIC_MAX(type) \
type type##_max(type x, type y)\
{ \
 return (x>y?x:y); \
}

使⽤宏,定义不同函数

GENERIC_MAX(int) //替换到宏体内后int##_max ⽣成了新的符号 int_max做函数名 
GENERIC_MAX(float) //替换到宏体内后float##_max ⽣成了新的符号 float_max做函数名 
int main()
{
 //调⽤函数 
 int m = int_max(2, 3);
 printf("%d\n", m);
 float fm = float_max(3.5f, 4.5f);
 printf("%f\n", fm);
 return 0;
}

输出:

3
4.500000

3. 条件编译

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

⽐如说:

调试性的代码,删除可惜,保留⼜碍事,所以我们可以选择性的编译。
#include <stdio.h>
#define __DEBUG__

int main()
{
    int i = 0;
    int arr[10] = { 0 };
    for (i = 0; i < 10; i++)
    {
        arr[i] = i;
#ifdef __DEBUG__
        printf("%d\n", arr[i]);//为了观察数组是否赋值成功。  
#endif //__DEBUG__
    }
    return 0;
}

常⻅的条件编译指令:

1.
#if 常量表达式
//...
#endif
//常量表达式由预处理器求值。 
如:
#define __DEBUG__ 1
#if __DEBUG__
//..
#endif

2.多个分⽀的条件编译
#if 常量表达式
//...
#elif 常量表达式
//...
#else
//...
#endif

3.判断是否被定义
#if defined(symbol)
#ifdef symbol

#if !defined(symbol)
#ifndef symbol

4.嵌套指令
#if defined(OS_UNIX)
	#ifdef OPTION1
		unix_version_option1();
	#endif
	
	#ifdef OPTION2
		unix_version_option2();
	#endif
	
#elif defined(OS_MSDOS)
	#ifdef OPTION2
		msdos_version_option2();
	#endif
	
#endif

4. 题目分享

  1. 写一个宏,计算结构体中某变量相对于首地址的偏移,并给出说明
    考察:offsetof宏的实现
#include<stdio.h>
#define offset(structType, MemberName) ((size_t)&((structType*)0)->MemberName)

struct stu
{
	char name[10];
	int age;
	char sex[10];
};

int main()
{
	size_t ret = 0;
	ret = offset(struct stu, age);
	printf("%d\n", ret);
	return 0;
}


运行结果:

在这里插入图片描述

代码分析:

//Struct是结构体类型名,MenberName是成员名.
//1、先将0转换为一个结构体类型的指针,
// 相当于某个结构体的首地址是0。
// 此时,每一个成员的偏移量就成了相对0的偏移量,
// 这样就不需要减去首地址了。
//
//2、对该指针用->访问其成员,并取出地址,
// 由于结构体起始地址为0,此时成员偏移量直接相当于对0的偏移量,
// 所以得到的值直接就是对首地址的偏移量。
//
//3、取出该成员的地址,强转成size_t并打印,就求出了这个偏移量。
  1. 写一个宏,可以将一个整数的二进制位的奇数位和偶数位交换。
#define SWAP_BITS(num) (((num & 0xAAAAAAAA) >> 1) | ((num & 0x55555555) << 1))

代码分析:

//交换奇偶位,需要先分别拿出奇偶位。
//既然是宏,分别拿出用循环不是很现实,
//那就用& 这些位的方式来做。奇数位拿出,
//那就是要& 上010101010101……,偶数位拿出,
//就是要& 上101010101010……,对应十六进制分别是555……和aaa……,
//一般我们默认是32位整数,4位对应一位16进制就是8个5,8个a。
//通过 & 0x55555555的方式拿出奇数位和 & 0xaaaaaaa的方式拿出偶数位。
//奇数位左移一位就到了偶数位上,偶数位右移一位就到了奇数位上,
//最后两个数字或起来,就完成了交换

总结

以上是本文的全部内容, 如果觉得有帮助还望点赞收藏, 如有错误恳请指正

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1618238.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【刷题】前缀和入门

送给大家一句话&#xff1a; 既然已经做出了选择&#xff0c;最好还是先假定自己是对的。焦虑未来和后悔过去&#xff0c;只经历一个就够了。 – 张寒寺 《不正常人类症候群》 ☆ミヾ(∇≦((ヾ(≧∇≦)〃))≧∇)ノ彡☆ ☆ミヾ(∇≦((ヾ(≧∇≦)〃))≧∇)ノ彡☆ ☆ミヾ(∇≦((ヾ…

比特币中的符文是什么?

比特币中的符文是什么&#xff1f; 比特币符文是存在于比特币区块链上的独特的、可替代的代币。它们旨在代表具有独特特征和元数据的可替代资产。 Ordinals 协议的创建者 Casey Rodamor 最近放弃了一项替代 BRC-20 可替代代币协议的提案&#xff0c;该替代方案被称为 Runes。 破…

STM32 HAL库F103系列之DAC实验(一)

DAC输出实验 原理图 DAC数据格式 DAC输出电压 DORX - 数据输出寄存器 Vref 3.3V 实验简要 1&#xff0c;功能描述 通过DAC1通道1(PA4)输出预设电压&#xff0c; 然后由ADC1通道1 (PA1) 采集&#xff0c;最后显示ADC转换的数字量及换算后的电压值 2&#xff0c;关闭通道1…

TypeError: Cannot read properties of undefined (reading ‘tapAsync‘)

项目启动&#xff0c;一直报tabAsync未定义&#xff0c;整个项目中没有找到引用的地方&#xff1b; 最终重新安装webpack4版本 解决问题&#xff1b; npm install webpack4

Android studio顶部‘app‘红叉- Moudle ‘XX.app’ dosen’t exist in project

Android studio顶部app红叉- Moudle ‘XX.app’ dosen’t exist in project 1、现象&#xff1a; 运行老项目或者有时候替换项目中的部分代码&#xff0c;明明没有错但是Android studio就编译报错了。 1.1 Android studio顶部app红叉。 1.2 点击Build没有clear菜单&#xff0…

掼蛋赢牌口诀

1、不能做头游&#xff0c;单张暂缓走。 2、起始出单张&#xff0c;表明有大王。 3、单牌先起步&#xff0c;对家应相助。 4、情况尚不明&#xff0c;对子可先行。 5、要想使个坏&#xff0c;就出三不带。 6、小顺往前凑&#xff0c;大顺必殿后。 7、哪张牌先下&#xff0c;倒数…

Electron+Vue3+ElectronForge整合 - 打包时整合 -分步打包

说明 本文介绍一下 Electron Vue3 的打包整合的基本操作。实现的效果是 &#xff1a; 1、一个正常的Vue3项目&#xff1b; 2、整合加入 Electron 框架 &#xff1a;开发时 Electron 加载的是开发的vue项目&#xff1b; 3、完成打包时整合&#xff1a;3.1 先完成vue3项目的正常…

情感识别——情感计算的模型和数据集调查

概述 情感计算指的是识别人类情感、情绪和感觉的工作&#xff0c;已经成为语言学、社会学、心理学、计算机科学和生理学等领域大量研究的主题。 本文将概述情感计算的重要性&#xff0c;涵盖思想、概念和方法。 情感计算是皮卡德于 1997 年提出的一个想法&#xff0c;此后出…

小案例:ToolBar+选项菜单

使用选项菜单&#xff0c;一般是用于做单选&#xff0c;需要重写方法&#xff1a; public boolean onCreateOptionsMenu(Menu menu) 如果想要实现事件监听&#xff0c;则采用基于回调的事件监听机制&#xff0c;可以监听到具体是哪一项被选中。即重写方法&#xff1a; publi…

基于Spring Boot的点餐平台网站设计与实现

基于Spring Boot的点餐平台网站设计与实现 开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/idea 系统部分展示 管理员登录界面&#xff0c;通过填写用户名、密码、角色…

OpenHarmony实战开发-性能测试工具SmartPerf Editor使用指导

概述 SmartPerf Editor是一款PC端桌面应用&#xff0c;通过监测、采集应用运行时FPS、CPU、GPU、Memory、Battery、Network等性能数据&#xff0c;帮助开发者了解应用的性能状况。SmartPerf Editor还集成了DrawingDoc功能&#xff0c;可录制Render Service绘制指令&#xff0c…

Idea如何本地调试线上测试服务器代码?

线上出现问题&#xff0c;但是没加日志打印拍脑门惋惜为啥不多打一行日志 加日志重新部署&#xff0c;半小时没了&#xff0c;问题还没有找到&#xff0c;头顶的灯却早已照亮了整层楼...... 排查别人线上的 bug&#xff0c;不仅代码还没看懂&#xff0c;还没一行日志&#…

Linux 终端中的目录切换

目录 ⛳️推荐 前言 理解 Linux 中的路径 利用 cd 命令变更目录 故障解决 文件或目录不存在 非目录错误 特殊目录符号 测试你的知识 ⛳️推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击…

AD 21、22 软件安装教程

AD2022安装包链接 链接&#xff1a;https://pan.baidu.com/s/1oMNbXibQ1Zjl0RTLdPDVGw 提取码&#xff1a;xfs4 软件下载 1.以管理员身份运行 2. 3. 4. 5.路径最好改为C盘以外的&#xff0c;如D盘&#xff0c;要新建一个空文件夹 6. 7.下载好以后 8.在Crack文件夹下找…

内插和抽取

抽取&#xff1a; 频域表达式的关系&#xff1a; 1、角频率扩大M倍 2、移动2pi、22pi…&#xff08;n-1&#xff09; 2pi 3、相加 4、幅度变为1/M 内插&#xff1a; 加入低通滤波&#xff0c;减小混叠&#xff0c;但是由于截短&#xff0c;也会造成误差&#xff0c;但是…

投资网站汇总

1、 中信证券(600030)历年财务指标——亿牛网https://eniu.com/gu/sh600030/cwzb 2、 3、 4、

Linux中文件描述符与重定向的深入探索

目录 1. 理解C语言的文件操作函数 2. 操作系统的文件操作接口 3. 文件描述符详解和其内核本质 4. 如何理解Linux下一切皆文件 5. Linux中的重定向 5.1 输出重定向 5.2 追加重定向 5.3 输入重定向 6. 结合文件描述符理解重定向 7.重定向的系统调用 在Linux操作系统中&a…

Docker容器:镜像与容器命令管理

目录 一、镜像管理命令 1、搜索镜像 2、获取镜像 3、镜像加速下载 4、查看下载的镜像文件信息 5、查看下载到本地的所有镜像 6、获取指定镜像的详细信息 7、为本地的镜像添加新的标签 8、删除镜像 8.1 删除指定的镜像 8.2 批量删除多个镜像 9、导出镜像与导入镜像 …

CUDA线程管理

核函数在主机端启动时&#xff0c;执行会转移到设备上&#xff0c;并且将控制权转移回主机。当核函数在GPU上运行时&#xff0c;主机可以运行其他函数。因此&#xff0c;主机与核函数是异步的。 此时&#xff0c;设备端也就是GPU上会产生大量的线程&#xff0c;并且每个线程都…

汇编期末复习知识点

参考文献1 第一章 概述 组成 计算机系统由硬件子系统和软件子系统组成。硬件子系统&#xff1a;组成计算机系统的所有电子的&#xff0c;机械的&#xff0c;光学的和磁性的元部件。 计算机中常用进制数表示 十进制(Decimal):数据尾部加一后缀D&#xff0c;如2355D二进制&a…