C++沉思:预处理和编译

预处理和编译

  • 条件编译源代码
    • 使用方式
    • 典型示例
    • 原理
  • 使用static_assert执行编译时断言检查
    • 使用方式
    • 原理

在C++中,编译是将源代码转换为机器代码并组织在目标文件中,然后将目标文件链接在一起生成可执行文件的过程。编译器实际上一次只处理一个文件,这个文件是由预处理器(编译器中处理预处理指令的部分)从单个源文件及其包含的所有头文件中生成的。

条件编译源代码

条件编译使开发人员能够维护单个代码库,但只考虑编译代码的某些部分,以生成不同的可执行文件(通常是为了在不同的平台或硬件上运行,或依赖于不同的库或版本)。

使用方式

若要条件编译部分代码,可以使用#if、#ifdef和#ifndef指令(与#elif、#else和#endif指令一起)。条件编译的一般形式如下:

#if condition1text1
#elif condition2text2
#elif condition3text3
#elsetext4
#endif

要定义用于条件编译的宏,可以使用以下方法之一:

  1. 在源代码中使用#define指令:

    #define VERBOSE_PRINTS
    #define VERBOSITY_LEVEL 5
    
  2. 使用编译器命令行选项
    对于g++而言:-D是一个选项,用于在编译时定义宏

    main.cpp

    #include <iostream>int main() {std::cout << "Hello, World!" << std::endl;#ifdef DEBUGstd::cout << "Debug mode is enabled." << std::endl;#elsestd::cout << "Debug mode is disabled." << std::endl;#endifreturn 0;
    }
    

    编译指令,定义宏DEBUG

    g++ -DDEBUG main.cpp -o main
    

    输出Debug mode is enabled.
    普通编译

    g++ main.cpp -o main
    

    输出Debug mode is disabled.

典型示例

  1. 头文件保护避免重复定义
    现在更多的使用:pragma once

    #ifndef HEADER_NAME
    #define HEADER_NAMEclass A {}
    #endif
    

    两者都可以实现头文件的防重复包含,但前者适用于所有遵循C/C++预处理器约定的编译器,后者则依赖于编译器的支持。

  2. 针对跨平台应用程序
    将带有编译器名称的消息打印到控制台

    void show_compiler() {
    #if defined _MSC_VERcout << "VC++\n";
    #elif defined __clang__cout << "Clang\n";
    #elif defined __GNUG__cout << "GCC\n";
    #elsecout << "unknown compiler\n";
    #endif
    }
    
  3. 针对多个架构的目标特定代码

    void show_architecture()
    {
    #if defined _MSC_VER#if defined _M_X64std::cout << "AMD64";#elif defined _M_IX86std::cout << "INTEL x86";#elif defined _M_ARMstd::cout << "ARM";#elsestd::cout << "unknown";#endif
    #elif defined __clang__ || __GNUC__#if defined __amd64__std::cout << "AMD64";#elif defined __i386__std::cout << "INTEL x86";#elif defined __arm__std::cout << "ARM";#elsestd::cout << "unknown";#endif
    #else#error Unknown compiler
    #endif
    }
    
  4. 特定于配置的代码
    有条件地编译调试和发布版本

    void show_configuration() {
    #ifdef _DEBUGcout << "debug\n";
    #else cout << "release\n";
    #endif
    }
    

原理

当使用预处理指令#if、#ifndef、#ifdef、#elif、#else和#endif时,编译器将至多选择一个分支,其主体将包含在编译单元中。这些指令的主体可以是任何文本,包括其他预处理指令。适用规则如下:

  1. #if、#ifdef和#ifndef必须用#endif匹配。
  2. #if指令可以有多条#elif指令,但只有一条#else指令,且#else必须是#endif之前的最后一条。
  3. #if、#ifdef、#ifndef、#elif、#else和#endif可以嵌套。
  4. #if指令需要一个常量表达式,而#ifdef和#ifndef则需要一个标识符。
  5. defined操作符可以用于预处理器常量表达式,但只能在#if和#elif指令中使用。
  6. defined(identifier)在定义identifier时为true,否则,它被认为是false。
  7. 定义为空文本的标识符被认为是有定义的。
  8. #ifdef identifier等价于#if defined(identifier)。
  9. #ifndef identifier等价于#if !defined(identifier)。
  10. defined(identifier)和defined identifier是等价的。
  11. 宏的名称在整个应用程序中必须是唯一的,否则,将只编译使用宏的第一个头文件中的代码

使用static_assert执行编译时断言检查

C++可以同时执行运行时和编译时断言检查。注意:C++版本需要高于>=C++11才会出现编译错误

  1. 运行时断言只有在程序运行时并且只有在控制流到达它们时才会被验证。当条件依赖于运行时数据时只能选择运行时断言。
  2. 编译时断言(条件可以在编译时求值)能够在开发阶段的早期通知某个特定条件未被满足。在C++11中,编译时断言是通过static_assert执行的。
  3. 静态断言检查常在模板元编程中用于验证模板类型的先决条件是否满足(例如类型是否为POD类型、可复制构造类型、引用类型等)。另一个典型用例是确保类型(或对象)具有预期的大小。

使用方式

使用 static_assert 声明来确保满足以下作用域中的条件:

  1. 命名空间作用域,本例验证item类的大小总是16

    struct alignas(8) item
    {int     id;bool    active;double  value;/* data */
    };static_assert(sizeof(item) == 16,"size of item must be 16 types");
    
  2. 类作用域,本例验证pod_wrapper只能与POD类型一起使用

    is_standard_layout_v 是 C++ 标准库 <type_traits> 中的一个模板元函数,它用于在编译时判断一个类型是否是标准布局类型。标准布局类型需要满足一系列规则,这些规则包括:

    • 没有虚函数(包括虚析构函数)
    • 没有虚基类
    • 所有非静态成员都是标准布局类型
    • 非静态成员之间没有相同的名称
    • 类的继承关系中没有相同的基类
    • 满足其他一些与对齐和大小相关的规则
    template <typename T>
    class pod_wrapper {static_assert(std::is_standard_layout_v<T>,"POD type expected!");T value;
    };struct point
    {int x;int y;/* data */
    };
    pod_wrapper<int>            w1;	//ok
    pod_wrapper<point>          w2;	//ok
    pod_wrapper<std::string>    w3;	//err
    
  3. 函数块作用域,本例验证函数模板是否只有整型参数

    #include <type_traits>template <typename T>
    auto mul(T const a, T const b) {static_assert(std::is_integral_v<T>::value,"Integral type expected");return a * b;
    }
    auto v1 = mul(1, 2);	//ok
    auto v2 = mul(1.2, 3.4);	//err
    

原理

static_assert是一个声明,但它没有引入新名称。这些声明的形式如下:

static_assert(condition, message);

该条件必须在编译时转换为布尔值,且消息必须是字符串字面量。在C++17中,该消息是可选的。当static_assert声明中的条件计算结果为true时,什么都不会发生;当条件的计算结果为false时,编译器生成一个包含指定消息(如果有的话)的错误。

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

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

相关文章

Oracle核心进程详解并kill验证

Oracle核心进程详解并kill验证 文章目录 Oracle核心进程详解并kill验证一、说明二、核心进程详解2.1.PMON-进程监控进程2.2.SMON-系统监控进程2.3.DBWn-数据库块写入进程2.4. LGWR-日志写入器进程2.5. CKPT-检查点进程 三、Kill验证3.1.kill ckpt进程3.2.kill pmon进程3.3.kill…

智慧工地视频汇聚管理平台:打造现代化工程管理的全新视界

一、方案背景 科技高速发展的今天&#xff0c;工地施工已发生翻天覆地的变化&#xff0c;传统工地管理模式很容易造成工地管理混乱、安全事故、数据延迟等问题&#xff0c;人力资源的不足也进一步加剧了监管不到位的局面&#xff0c;严重影响了施工进度质量和安全。 视频监控…

中小企业数字化转型的关键五步,你了解吗?

在信息技术迅猛发展的当下&#xff0c;数字化转型已成为中小企业提升竞争力、实现可持续发展的关键策略。在数字化转型过程中&#xff0c;工业软件作为贯穿生产全流程的智能化引擎&#xff0c;其选择与应用显得尤为关键。那么&#xff0c;中小企业应如何科学合理的规划数字化转…

Vue前端页面嵌入mermaid图表--流程图

一、安装Mermaid 首先&#xff0c;你需要在你的项目中安装Mermaid。可以通过npm或yarn来安装&#xff1a; npm install mermaid --save # 或者 yarn add mermaid结果如图&#xff1a; 二、Vue 方法一&#xff1a;使用pre标签 使用ref属性可以帮助你在Vue组件中访问DOM元素 …

对于接口调用方式,可以使用两种不同的技术:Web Service 和 Dubbo。下面我将简要解释它们以及如何在 Maven 项目中集成它们。

对于接口调用方式&#xff0c;可以使用两种不同的技术&#xff1a;Web Service 和 Dubbo。下面我将简要解释它们以及如何在 Maven 项目中集成它们。 ### 1. Web Service&#xff08;WS&#xff09; Web Service 是一种基于标准化协议和格式进行通信的技术&#xff0c;允许不同…

数据结构 | LinkedList与链表

前言 ArrayList底层使用连续的空间,任意位置(尤其是0位置下标)插入或删除元素时,需要将该位置后序元素 整体 往前或往后搬移,故时间复杂度为O(N). 优点(给定一个下标,可以快速查找到对应的元素,时间复杂度为O(1))增容需要申请新空间,拷贝数据,释放旧空间,会有不小的消耗.增容一…

【权威发布】第二届雷达、信号与信息处理国际会议(RSIP 2024)

第二届雷达、信号与信息处理国际会议 2024 International Conference on Radar, Signal and Information Processing 【1】会议简介 第二届雷达、信号与信息处理国际会议是一次聚焦雷达技术、信号处理及信息处理领域最新研究成果和前沿趋势的盛会。会议旨在汇聚国内外雷达与信号…

【Django】anaconda环境变量配置及配置python虚拟环境

文章目录 配置环境变量配置python虚拟环境查看conda源并配置国内源在虚拟环境中安装django 配置环境变量 control sysdm.cpl,,3笔者anaconda安装目录为C:\ProgramData\anaconda3 那么需要加入path中的有如下三个 C:\ProgramData\anaconda3 C:\ProgramData\anaconda3\Scripts C:…

【C++】类和对象(三)完结篇

个人主页 创作不易&#xff0c;感谢大家的关注&#xff01; 文章目录 ⭐一、再探构造函数1.初始化列表 &#x1f389;二、类型转换&#x1f3e0;三、static成员&#x1f3dd;️四、友元⏱️五、内部类&#x1f388;六、匿名对象&#x1f3a1;七、在拷贝对象时的编译器优化 ⭐一…

火焰传感器 - 从零开始认识各种传感器【第十六期】

火焰传感器|从零开始认识各种传感器 1、什么是火焰传感器 火焰传感器是一种用于检测火焰或火光的传感器。它可以快速、准确地检测到周围环境中火源的存在&#xff0c;从而在火灾发生之初及时向消防人员或相关机构发送报警信息&#xff0c;以便及时采取措施进行火灾扑救。此外…

C# 贪吃蛇游戏

贪吃蛇游戏可分为手动玩法和自动玩法 冯腾飞/贪吃蛇

【网络安全学习】 SQL注入01:基础知识

&#x1f4bb; 1. 什么是SQL注入 SQL注入是一种针对Web程序中数据库层的安全漏洞的攻击方式。它利用了程序对用户输入数据合法性的判断或过滤不严&#xff0c;允许攻击者在设计不良的程序中添加额外的SQL语句&#xff0c;从而执行计划外的命令或访问未授权的数据。攻击者可以通…

Docker搭建私有仓库harbor(docker 镜像仓库搭建)

Harbor介绍 Docker容器应用的开发和运行离不开可靠的镜像管理&#xff0c;虽然Docker官方也提供了公共的镜像仓库&#xff0c;但是从安全和效率等方面考虑&#xff0c;部署我们私有环境内的Registry也是非常必要的。Harbor是由VMware公司开源的企业级的Docker Registry管理项目…

Android statsd 埋点简析

源码基于&#xff1a;Android U 0. 前言 最近在研究 Android 自带的系统数据指标采集功能&#xff0c;框架依旧很严谨、完美&#xff0c;这里做个分享。 1. Android S 之后变化 stats 的代码从 framework 或 system/core 中转移到了 packages/modules/StatsD 目录中。 2. 框架…

IEC104转MQTT网关轻松将IEC104设备数据传输到Zabbix、阿里云、华为云、亚马逊AWS、ThingsBoard、Ignition云平台

随着工业4.0的深入发展和物联网技术的广泛应用&#xff0c;IEC 104&#xff08;IEC 60870-5-104&#xff09;作为电力系统中的重要通信协议&#xff0c;正逐步与各种现代监控、管理和云平台实现深度融合。IEC104转MQTT网关BE113作为这一融合过程中的关键设备&#xff0c;其能够…

动手学深度学习V2每日笔记(模型选择+过拟合和欠拟合)

本文主要参考沐神的视频教程 https://www.bilibili.com/video/BV1K64y1Q7wu/?spm_id_from333.788.recommend_more_video.0&vd_sourcec7bfc6ce0ea0cbe43aa288ba2713e56d 文档教程 https://zh-v2.d2l.ai/ 本文的主要内容对沐神提供的代码中个人不太理解的内容进行笔记记录&a…

通过IEC104转MQTT网关轻松接入阿里云平台

随着智能电网和物联网技术的飞速发展&#xff0c;电力系统中的传统IEC 104协议设备正面临向现代化、智能化转型的迫切需求。阿里云作为全球领先的云计算服务提供商&#xff0c;其强大的物联网平台为IEC 104设备的接入与数据处理提供了强大的支持。本文将深入探讨钡铼网关在MQTT…

linux查看某个是否被占用以及释放端口

在 Linux 系统中&#xff0c;可以使用多种方法来检查某个端口是否被占用&#xff0c;并释放该端口。以下是详细的步骤&#xff1a; 1. 检查端口是否被占用 使用 netstat sudo netstat -tuln | grep <port_number>例如&#xff0c;要检查端口 8080 是否被占用&#xff…

UML通信图建模技术及应用例

新书速览|《UML 2.5基础、建模与设计实践》 在对系统的动态行为进行建模时&#xff0c;通信图常被用于按组织结构对控制流进行建模。与顺序图一样&#xff0c;一个单独的通信图只能显示一个控制流。 使用通信图建模时可以遵循如下策略&#xff1a; &#xff08;1&#xff09…

WinDbg用户模式调试基础

WinDbg用户模式调试基础 在前面的文章中&#xff0c;介绍了如何使用WinDbg分析蓝屏原因https://www.cnblogs.com/zhaotianff/p/15150244.html 不过那会都是在网上找的资料&#xff0c;东拼西凑出来&#xff0c;并没有系统的去学习WinDbg。 最近在学习内核开发这一块的内容&…