[C++基础编程]----预处理指令简介、typedef关键字和#define预处理指令之间的区别

目录

引言         

正文         

01-预处理指令简介        

02-typedef关键字简介        

03-#define预处理指令简介        

04-#define预处理指令和typedef关键字的区别        

(1)原理不同

(2)功能不同

(3)作用域不同

(4)对指针的操作不同

总结         


引言         

        在C++中,预处理指令是在编译程序之前由预处理器处理的特殊指令。它们以井号(#)开头,用于在编译代码之前执行一些文本替换和条件编译。预处理指令不是真正的C++代码,而是在编译器之前进行处理的指令。

        以下是几个常用的预处理指令:

        a、#include: 用于包含头文件。例如,#include <iostream> 会在编译时将iostream文件的内容包含到当前文件中。

        b、#define: 用于定义符号常量。例如,#define PI 3.14159 可以定义一个名为PI的符号常量,它的值为3.14159。

        c、#ifdef, #ifndef, #endif: 这些指令用于条件编译。例如,#ifdef DEBUG 可以检查是否定义了DEBUG符号常量,如果定义了,则编译下面的代码块。

        d、#if, #elif, #else: 用于条件编译,类似于C++中的if语句。例如,#if X > Y 编译器会检查X是否大于Y,如果是,则编译下面的代码块。

        e、#error: 用于在预处理阶段生成编译错误。例如,#error “Unsupported platform” 会生成一个编译错误,指示编译器不支持当前平台。

正文         

01-预处理指令简介        

        (1)#include        

        当使用 #include 预处理指令时,是在告诉编译器在编译当前文件之前将指定的头文件内容包含进来。这是一种非常常见的方式,用来在代码中引入其他文件中定义的函数、变量、类等内容,以便在当前文件中使用它们,从而实现代码的模块化和复用。

        下面是一个具体的示例:假设有一个名为 main.cpp 的文件,这个文件中使用 iostream 头文件中定义的 cout 对象,以便能够在控制台输出信息。

        在这个示例中,#include <iostream> 将 iostream 头文件的内容包含到了 main.cpp 文件中。因此,你可以在 main.cpp 中直接使用 std::cout,而不需要重新定义它。这样做的好处是,可以在多个文件中共享同一个头文件中定义的内容,避免了重复编写相同的代码,提高了代码的可维护性和可重用性。

// main.cpp
#include <iostream> // 包含iostream头文件int main() {std::cout << "Hello, world!" << std::endl; // 使用iostream中的cout对象输出信息return 0;
}

        (2)#ifdef, #ifndef, #endif       

        #ifdef: 当定义了某个符号常量时,就会执行后面的代码。如果未定义该符号常量,则忽略后面的代码。下面是一个示例:

        在这个示例中,由于定义了DEBUG符号常量,因此输出"Debug mode is enabled"。如果注释掉#define DEBUG这行,那么#ifdef DEBUG中的代码就会被忽略。

#define DEBUG // 定义DEBUG符号常量#ifdef DEBUGstd::cout << "Debug mode is enabled" << std::endl;
#endif

  #ifndef: 与#ifdef相反,当未定义某个符号常量时,才会执行后面的代码。如果已定义了该符号常量,则忽略后面的代码。示例如下:

        在这个示例中,由于RELEASE未被定义,因此输出"Not in release mode"。

#ifndef RELEASE // RELEASE未定义std::cout << "Not in release mode" << std::endl;
#endif

  #endif: 用于结束#ifdef#ifndef的条件编译区域。示例如下:

        在这个示例中,如果定义了DEBUG则输出"Debug mode is enabled",否则输出"Debug mode is disabled"。

#ifdef DEBUGstd::cout << "Debug mode is enabled" << std::endl;
#elsestd::cout << "Debug mode is disabled" << std::endl;
#endif

      (3)#if, #elif, #else       

        在C++中,#if#elif 和 #else 是条件编译的预处理指令,与 #ifdef#ifndef 和 #endif 类似,用于根据指定的条件来选择性地编译代码段。下面是它们的详细说明和代码示例:

  #if: 根据给定的条件进行条件编译。如果条件为真,则编译后面的代码;否则,忽略后面的代码。示例如下:

        在这个示例中,如果 DEBUG_LEVEL 的值大于1,则输出"Debugging level is high"。如果 DEBUG_LEVEL 不大于1,那么这段代码就会被忽略。

#if DEBUG_LEVEL > 1std::cout << "Debugging level is high" << std::endl;
#endif

   #elif: 用于在多个条件之间进行选择,相当于 “else if”。示例如下:

        在这个示例中,如果 DEBUG_LEVEL 的值为2,则输出"Debugging level is medium";如果 DEBUG_LEVEL 的值为1,则输出"Debugging level is low";否则输出"Debugging level is off"。

#if DEBUG_LEVEL == 2std::cout << "Debugging level is medium" << std::endl;
#elif DEBUG_LEVEL == 1std::cout << "Debugging level is low" << std::endl;
#elsestd::cout << "Debugging level is off" << std::endl;
#endif

   #else: 用于在前面的条件都不满足时执行的代码。示例如下:

        在这个示例中,如果定义了DEBUG符号常量,则输出"Debug mode is enabled";否则输出"Debug mode is disabled"。

#if defined(DEBUG)std::cout << "Debug mode is enabled" << std::endl;
#elsestd::cout << "Debug mode is disabled" << std::endl;
#endif

      (4)#error     

        #error 预处理指令在 C++ 中用于产生编译错误,并显示指定的错误消息。这个指令通常用于在编译时检测到某些条件不满足时,中断编译过程并输出错误信息,以提示开发者进行修复。

        下面是详细的说明和代码示例:在这个示例中,如果 DEBUG 符号常量被定义,编译过程将中断,并显示错误消息"Debug mode is enabled. Disable debug mode before compiling for release."。这可以帮助确保在发布版本中不会意外地包含调试相关的内容或功能。

#if defined(DEBUG)// 如果定义了DEBUG符号常量,则编译出错并显示错误消息#error Debug mode is enabled. Disable debug mode before compiling for release.
#endif

02-typedef关键字简介        

        typedef 是一个关键字,而不是预处理指令。它用于为已有的类型取一个新的名字,使得代码更易读并且更具可移植性。

        下面是详细的说明和代码示例:在这个示例中,typedef 关键字用于为 int 类型取一个新的名字 Integer,从而在代码中可以用 Integer 代替 int。这样代码看起来更清晰,并且如果需要修改数据类型时,只需在 typedef 的地方进行修改,而不必在所有代码中逐一修改。

typedef int Integer; // 将"int"类型取一个别名为"Integer"Integer x = 10; // 定义一个整型变量x,并赋值为10// 使用新定义的别名Integer
void printInteger(Integer num) {std::cout << "The integer is: " << num << std::endl;
}printInteger(x); // 调用函数打印变量x的值

03-#define预处理指令简介        

        #define 是C++中用于创建宏的预处理指令。它允许您定义一个带有名称的常量或者带有参数的函数样式宏。宏定义会在编译之前进行文本替换。

        下面是详细的说明和代码示例:

        (1)定义常量:

#define PI 3.14159// 使用宏定义的常量
double circleArea(double radius) {return PI * radius * radius;
}

        在这个示例中,#define PI 3.14159 定义了一个名为 PI 的常量,它代表圆周率。在函数 circleArea 中,可以直接使用 PI 来计算圆的面积。

        (2)定义带参数的宏:

#define SQUARE(x) ((x) * (x))// 使用带参数的宏
int main() {int result = SQUARE(5);std::cout << "Square of 5 is: " << result << std::endl; // 输出 25return 0;
}

        在这个示例中,#define SQUARE(x) ((x) * (x)) 定义了一个名为 SQUARE 的宏,它接受一个参数 x,并返回 x 的平方。在 main 函数中,SQUARE(5) 将被替换为 (5) * (5),最终计算出结果为 25。

        注:使用 #define 宏可以简化代码、提高可读性,但要注意它们的一些潜在问题,比如可能引发意外的副作用,因为它只是简单的文本替换。

04-#define预处理指令和typedef关键字的区别        

        #define预处理指令和typedef关键字的区别如下:

      (1)原理不同

  #define 预处理指令: #define 实质上是一个简单的文本替换机制。它在预处理阶段将指定的文本字符串替换为另一个字符串或表达式。

        这段代码将在预处理阶段将所有出现的 PI 替换为 3.14159

#define PI 3.14159

  typedef 关键字: typedef 是用于为数据类型定义一个新的名称,它在编译器层面上为给定的数据类型创建一个别名。

        这段代码在编译器层面为 int 类型创建了一个别名 Integer

typedef int Integer;

     (2)功能不同

  #define 预处理指令: 主要用于创建宏,可以用来定义常量、函数样式宏等。它提供了一种简单的文本替换机制,可以用于代码中的任何地方。

        这个示例定义了一个常量 MAX_SIZE,用于表示数组的最大大小。

#define MAX_SIZE 100

  typedef 关键字: 用于为已有的数据类型创建一个新的名称,使代码更易读并增加可移植性。它允许在代码中引入自定义的类型名称,以增强代码的可读性和可维护性。

        这个示例创建了一个别名 Integer,用于表示 int 类型。

typedef int Integer;

    (3)作用域不同

  #define 预处理指令: 宏定义的作用域是全局的,即从定义处到文件结束或另一条取消宏定义的指令为止。

        该宏定义的作用域是全局的,从定义处到文件结束或另一条取消宏定义的指令为止。

#define MAX_SIZE 100

  typedef 关键字: 类型别名的作用域是局部的,它只在定义它的作用域内有效。

        类型别名的作用域是局部的,只在定义它的作用域内有效。

typedef int Integer;

    (4)对指针的操作不同

  #define 预处理指令: #define 可以用来创建函数样式宏,包括指针操作。但它只是简单的文本替换,可能会导致一些不直观的行为。

        这段代码创建了一个指针类型的宏定义 PTR_INT,它可能引发一些不直观的行为。

#define PTR_INT int*

  typedef 关键字: typedef 可以创建指针类型的别名,使得对指针更加清晰易懂。通过 typedef 可以创建更具有语义的指针类型,增强代码的可读性。

        这段代码创建了一个指针类型的别名 IntPtr,使得指针类型更加清晰易懂。

typedef int* IntPtr;

        下面这个示例中,#define 定义了一个常量 MAX_SIZE 和一个交换两个数值的函数样式宏 SWAP。而 typedef 则定义了两个类型别名 Integer 和 IntPtr,分别表示整数和整型指针。

// #define 示例
#define MAX_SIZE 100// 定义函数样式宏,交换两个数值
#define SWAP(x, y) { int temp = x; x = y; y = temp; }// typedef 示例
typedef int Integer; // 将int类型取别名为Integer
typedef int* IntPtr; // 将int指针类型取别名为IntPtrint main() {// #define 示例int arr[MAX_SIZE]; // 使用常量定义数组大小int a = 5, b = 10;SWAP(a, b); // 使用函数样式宏交换a和b的值// typedef 示例Integer num = 100; // 使用别名Integer定义变量IntPtr ptr = &num; // 使用别名IntPtr定义指针变量return 0;
}

总结         

       预处理指令在C++中可以用来控制编译过程、优化代码、进行平台适配等,是编写高效、可维护程序的重要工具之一。但是过度使用预处理指令可能会导致代码复杂难懂,因此在使用时需要谨慎并遵循良好的编程实践。

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

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

相关文章

TEA: Temporal Excitation and Aggregation for Action Recognition 论文阅读

TEA: Temporal Excitation and Aggregation for Action Recognition 论文阅读 Abstract1. Introduction2. Related Works3. Our Method3.1. Motion Excitation (ME) Module3.1.1 Discussion with SENet 3.2. MultipleTemporal Aggregation(MTA) Module3.3. Integration with Re…

QT如何增删安装的组件

打开 uninstall QT 往下会看到让你选择 add or remove component。 接下去就可以修改组件了

Python快速入门-零基础也能掌握的编程技巧,基础方法和API整理

目录 前言 数据结构 数字 数学运算 随机数 字符串 列表 元组 字典 面向对象 JSON 文件操作 扩展 制作一个简易时钟 前言 环境什么就不在赘述&#xff0c;可以参考其他文章&#xff0c;也可以在线运行 CSDN在线运行地址&#xff1a;InsCode - 让你的灵感立刻落地…

Amesim基础篇-热仿真常用模型库-Thermal Hydraulic /Resistance

有言在先 流体库、管路库在热管理中是必备模块&#xff0c;如动力电池液冷循环系统均需要Thermal Hydraulic /Resistance库的元件建模。 1 流体物性设置 AMEsim中内嵌了大部分液冷的热物性&#xff0c;直接在流体子模型上选择即可。常规使用的是50%乙二醇水溶液&#xff0c;如…

水表智能抄表系统是什么?

水表智能抄表系统是一种现代化水资源保护专用工具&#xff0c;它利用先进的物联网、云计算和大数据剖析&#xff0c;完成了智能抄表、实时监控系统、数据分析等作用&#xff0c;大大提高了水务管理的效率和精确性。 1.功能特点 1.1远程控制自动抄表 传统水表抄水表方法采用人…

sentinel-dashborard下发流控规则未生效排查解决

Sentinel简介 Sentinel是阿里巴巴开源的一个流量控制组件&#xff0c;它以流量为切入点&#xff0c;从流量控制、熔断降级、系统负载保护等多个维度来保护服务的稳定性。Sentinel的核心思想是&#xff1a;通过动态设置的规则&#xff0c;对进入系统的流量进行控制&#xff0c;…

C#知识|将选中的账号信息展示到控制台(小示例)

哈喽&#xff0c;你好啊&#xff0c;我是雷工&#xff01; 上篇学习了控件事件的统一关联&#xff0c; 本篇通过实例练习继续学习事件统一处理中Tag数据获取、对象的封装及泛型集合List的综合运用。 01 实现功能 在上篇的基础上实现&#xff0c;点击选中喜欢的账号&#xff0…

如何将Hyper-V转VMware?反之亦可

为何要在Hyper-V和VMware之间进行转换呢&#xff1f; 尽管VMware和Microsoft Hyper-V都是当前流行的一类虚拟机监控程序&#xff0c;但它们并不相互兼容。VMware产品使用VMDK格式创建虚拟磁盘&#xff0c;而Hyper-V则使用VHD或VHDX格式创建虚拟磁盘。 有时您可能需要进行这种转…

Edge视频增强功能

edge://flags/#edge-video-super-resolution 搜索Video查找 Microsoft Video Super Resolution 设置为Enabled

凸优化理论学习一|最优化及凸集的基本概念

文章目录 一、优化问题&#xff08;一&#xff09;数学优化&#xff08;二&#xff09;凸优化 二、凸集&#xff08;一&#xff09;一些标准凸集&#xff08;二&#xff09;保留凸性的运算&#xff08;三&#xff09;正常锥和广义不等式&#xff08;四&#xff09;分离和支撑超…

计数问题C++

题目&#xff1a; 思路&#xff1a; 1~n之间进行循环遍历&#xff0c;如果i不等于0继续循环&#xff0c;然后求出i的个位数与十位数&#xff0c;如果个位数为要查找的特定数字&#xff0c;计时器就1. 代码&#xff1a; #include<iostream> using namespace std; int n,x…

短视频收益分成一览表​​​​​​​​​​​​​​​​,视频号怎么做有收益的

今日为大家揭秘一个热门视频号的操作技巧。很多人都已经操作这类账号&#xff0c;并从中获益。视频号目前是市场上非常热门的平台之一&#xff0c;流量之大令人惊叹&#xff0c;先不提那些私域营销的巨大优势&#xff0c;仅从创作分成计划角度来看&#xff0c;已有许多人每天能…

react18【系列实用教程】useEffect —— 副作用操作 (2024最新版)

什么是副作用操作&#xff1f; useEffect 用于编写由渲染本身引起的对接组件外部的操作&#xff08;官方称呼为&#xff1a;副作用操作&#xff09; 以下情况会触发页面渲染 初次加载页面&#xff08;组的挂载&#xff09;响应式变量发生变化&#xff0c;触发页面根据新值重新…

死锁调试技巧:工作线程和用户界面线程

有人碰到了一个死锁问题&#xff0c;找到我们想请我们看看&#xff0c;这个是关于应用程序用户界面相关的死锁问题。 我也不清楚他为什么会找上我们&#xff0c;可能是因为我们经常会和窗口管理器打交道吧。 下面&#xff0c;我们来看看死锁的两个线程。 >> 请移步至 …

软件工程经济学--期末复习资料

软件工程经济学--期末复习资料 前言第一章 绪论第二章 软件工程经济学基础第三章 软件的成本管理与定价分析第四章 软件工程项目评价方法与经济效果评价第五章 软件生产函数、效益分析及不确定性分析第六章 软件工程项目进度计划的制定结尾总结 前言 软件工程经济学&#xff0…

Java 开发 框架安全:Spring 漏洞序列.(CVE-2022-22965)

什么叫 Spring 框架. Spring 框架是一个用于构建企业级应用程序的开源框架。它提供了一种全面的编程和配置模型&#xff0c;可以简化应用程序的开发过程。Spring 框架的核心特性包括依赖注入&#xff08;Dependency Injection&#xff09;、面向切面编程&#xff08;Aspect-Or…

计算机服务器中了devicdata勒索病毒如何解密,devicdata勒索病毒解密恢复工具

在网络技术飞速发展的时代&#xff0c;有效地利用网络开展各项工作业务&#xff0c;能够大大提升企业的生产运行效率&#xff0c;改善企业的发展运营模式&#xff0c;但如果网络利用不好就会给企业的数据安全带来严重威胁。近日&#xff0c;云天数据恢复中心接到很多企业的求助…

centos7.9升级4.19内核

centos默认的内核版本是3.10 通过命令 uname -a 输出系统的详细信息 在部署k8s集群时使用默认的3.10版本的内核&#xff0c;容易出各种奇奇怪怪的问题、可以理解为docker和k8s与该内核版本不兼容&#xff0c;所以在部署k8s集群时&#xff0c;务必要升级内核&#xff0c;这里…

ESP32重要库示例详解(一):EEPROM之Preferences库

1. 了解EEPROM 在嵌入式系统开发中&#xff0c;断电后晚能存储少量数据是常见需求。EEPROM&#xff08;Electrically Erasable Programmable Read-Only Memory&#xff09;是一种非易失性存储器&#xff0c;即使断电数据也不会丢失。ESP32的EEPROM模拟功能利用闪存空间&#x…

移动硬盘加了PD充电口给设备供电:未来存储与供电的完美结合

添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 一、引言 随着科技的飞速发展&#xff0c;电子设备在人们的日常生活中扮演着越来越重要的角色。与此同时&#xff0c;设备间的互联互通和供电方式的便捷性也成为了用户关注的焦点。移动硬盘&#xff0c;作…