【C&C++ Tip 01】#define, __cplusplus, extern "C"

本文介绍了C++中的#define预处理指令,包括防止头文件重复引用、宏定义常量、连接操作符##、类型转换以及在Linux中安全的min宏定义。还讲解了__cplusplus宏的作用,用于识别C++代码,并讨论了extern "C"在C++中调用C库的用法,以保持函数名的兼容性。

注:基础知识学习积累所用,参考网上资料,后续扩展。


【定义】#define是预处理指令,在编译预处理时进行简单的文本替换,不做类型检查。
【格式】#define KEY value, 编译会把所有KEY文本替换为value.
【目的】1. #ifndef和 #define组合,一般用于头文件中,用以实现防止多个文件对此同一个头文件的重复引用。
#ifndef <标识>
#define <标识>
……
// include or define sth.
……
#endif

2.#ifdef和 #define组合,可以实现加入自己需要的模块(源文件).
#ifdef MYSELF_H
#include “myself.c”
#endif

3.#define可以进行宏定义常量
可以对一些常见的变量,字符串等,进行宏定义,系统在编译期间,就会自动替换。


1. #define只带一个参数(例#define JDK_1.4)

定义宏,并在预处理过程中将其替换为空字符串(即删除),表示已定义JDK_1.4, 通过#ifdef判断返回true。
这样做主要是为了标记某些内容,使程序阅读者能够清楚标记表明的意义,同时又不影响被编译的源代码。
通常这些标记能被条件编译的预处理命令#ifdef、#ifndef检测到, 可在别处引用该文件进,用此空的宏作条件判断。

2. #define Conn(x,y) x##y

x##y, 表示x连接y,举例说:
int n = Conn(123, 456); 结果就是n=123456;
char* str = Conn(“asdf”, “adf”)结果就是 str = “asdfadf”;
如#define A(x) T_##x == A(1)——>T_1

/** ****************************************************************************** * @file stm32f1xx.h * @author MCD Application Team * @brief CMSIS STM32F1xx Device Peripheral Access Layer Header File. * * The file is the unique include file that the application programmer * is using in the C source code, usually in main.c. This file contains: * - Configuration section that allows to select: * - The STM32F1xx device used in the target application * - To use or not the peripheral's drivers in application code(i.e. * code will be based on direct access to peripheral's registers * rather than drivers API), this option is controlled by * "#define USE_HAL_DRIVER" * ****************************************************************************** * @attention * * Copyright (c) 2017-2021 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /** @addtogroup CMSIS * @{ */ /** @addtogroup stm32f1xx * @{ */ #define STM32F103x8//(实际改成6) #ifndef __STM32F1XX_H #define __STM32F1XX_H #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /** @addtogroup Library_configuration_section * @{ */ /** * @brief STM32 Family */ #if !defined (STM32F1) #define STM32F1 #endif /* STM32F1 */ /* Uncomment the line below according to the target STM32L device used in your application */ #if !defined (STM32F100xB) && !defined (STM32F100xE) && !defined (STM32F101x6) && \ !defined (STM32F101xB) && !defined (STM32F101xE) && !defined (STM32F101xG) && !defined (STM32F102x6) && !defined (STM32F102xB) && !defined (STM32F103x6) && \ !defined (STM32F103xB) && !defined (STM32F103xE) && !defined (STM32F103xG) && !defined (STM32F105xC) && !defined (STM32F107xC) /* #define STM32F100xB */ /*!< STM32F100C4, STM32F100R4, STM32F100C6, STM32F100R6, STM32F100C8, STM32F100R8, STM32F100V8, STM32F100CB, STM32F100RB and STM32F100VB */ /* #define STM32F100xE */ /*!< STM32F100RC, STM32F100VC, STM32F100ZC, STM32F100RD, STM32F100VD, STM32F100ZD, STM32F100RE, STM32F100VE and STM32F100ZE */ /* #define STM32F101x6 */ /*!< STM32F101C4, STM32F101R4, STM32F101T4, STM32F101C6, STM32F101R6 and STM32F101T6 Devices */ /* #define STM32F101xB */ /*!< STM32F101C8, STM32F101R8, STM32F101T8, STM32F101V8, STM32F101CB, STM32F101RB, STM32F101TB and STM32F101VB */ /* #define STM32F101xE */ /*!< STM32F101RC, STM32F101VC, STM32F101ZC, STM32F101RD, STM32F101VD, STM32F101ZD, STM32F101RE, STM32F101VE and STM32F101ZE */ /* #define STM32F101xG */ /*!< STM32F101RF, STM32F101VF, STM32F101ZF, STM32F101RG, STM32F101VG and STM32F101ZG */ /* #define STM32F102x6 */ /*!< STM32F102C4, STM32F102R4, STM32F102C6 and STM32F102R6 */ /* #define STM32F102xB */ /*!< STM32F102C8, STM32F102R8, STM32F102CB and STM32F102RB */ /* #define STM32F103x6 */ /*!< STM32F103C4, STM32F103R4, STM32F103T4, STM32F103C6, STM32F103R6 and STM32F103T6 */ /* #define STM32F103xB */ /*!< STM32F103C8, STM32F103R8, STM32F103T8, STM32F103V8, STM32F103CB, STM32F103RB, STM32F103TB and STM32F103VB */ /* #define STM32F103xE */ /*!< STM32F103RC, STM32F103VC, STM32F103ZC, STM32F103RD, STM32F103VD, STM32F103ZD, STM32F103RE, STM32F103VE and STM32F103ZE */ /* #define STM32F103xG */ /*!< STM32F103RF, STM32F103VF, STM32F103ZF, STM32F103RG, STM32F103VG and STM32F103ZG */ /* #define STM32F105xC */ /*!< STM32F105R8, STM32F105V8, STM32F105RB, STM32F105VB, STM32F105RC and STM32F105VC */ /* #define STM32F107xC */ /*!< STM32F107RB, STM32F107VB, STM32F107RC and STM32F107VC */ #endif /* Tip: To avoid modifying this file each time you need to switch between these devices, you can define the device in your toolchain compiler preprocessor. */ #if !defined (USE_HAL_DRIVER) /** * @brief Comment the line below if you will not use the peripherals drivers. In this case, these drivers will not be included and the application code will be based on direct access to peripherals registers */ /*#define USE_HAL_DRIVER */ #endif /* USE_HAL_DRIVER */ /** * @brief CMSIS Device version number */ #define __STM32F1_CMSIS_VERSION_MAIN (0x04) /*!< [31:24] main version */ #define __STM32F1_CMSIS_VERSION_SUB1 (0x03) /*!< [23:16] sub1 version */ #define __STM32F1_CMSIS_VERSION_SUB2 (0x04) /*!< [15:8] sub2 version */ #define __STM32F1_CMSIS_VERSION_RC (0x00) /*!< [7:0] release candidate */ #define __STM32F1_CMSIS_VERSION ((__STM32F1_CMSIS_VERSION_MAIN << 24)\ |(__STM32F1_CMSIS_VERSION_SUB1 << 16)\ |(__STM32F1_CMSIS_VERSION_SUB2 << 8 )\ |(__STM32F1_CMSIS_VERSION_RC)) /** * @} */ /** @addtogroup Device_Included * @{ */ #if defined(STM32F100xB) #include "stm32f100xb.h" #elif defined(STM32F100xE) #include "stm32f100xe.h" #elif defined(STM32F101x6) #include "stm32f101x6.h" #elif defined(STM32F101xB) #include "stm32f101xb.h" #elif defined(STM32F101xE) #include "stm32f101xe.h" #elif defined(STM32F101xG) #include "stm32f101xg.h" #elif defined(STM32F102x6) #include "stm32f102x6.h" #elif defined(STM32F102xB) #include "stm32f102xb.h" #elif defined(STM32F103x6) #include "stm32f103x6.h" #elif defined(STM32F103xB) #include "stm32f103xb.h" #elif defined(STM32F103xE) #include "stm32f103xe.h" #elif defined(STM32F103xG) #include "stm32f103xg.h" #elif defined(STM32F105xC) #include "stm32f105xc.h" #elif defined(STM32F107xC) #include "stm32f107xc.h" #else #error "Please select first the target STM32F1xx device used in your application (in stm32f1xx.h file)" #endif /** * @} */ /** @addtogroup Exported_types * @{ */ typedef enum { RESET = 0, SET = !RESET } FlagStatus, ITStatus; typedef enum { DISABLE = 0, ENABLE = !DISABLE } FunctionalState; #define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE)) typedef enum { SUCCESS = 0U, ERROR = !SUCCESS } ErrorStatus; /** * @} */ /** @addtogroup Exported_macros * @{ */ #define SET_BIT(REG, BIT) ((REG) |= (BIT)) #define CLEAR_BIT(REG, BIT) ((REG) &= ~(BIT)) #define READ_BIT(REG, BIT) ((REG) & (BIT)) #define CLEAR_REG(REG) ((REG) = (0x0)) #define WRITE_REG(REG, VAL) ((REG) = (VAL)) #define READ_REG(REG) ((REG)) #define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK))) #define POSITION_VAL(VAL) (__CLZ(__RBIT(VAL))) /* Use of CMSIS compiler intrinsics for register exclusive access */ /* Atomic 32-bit register access macro to set one or several bits */ #define ATOMIC_SET_BIT(REG, BIT) \ do { \ uint32_t val; \ do { \ val = __LDREXW((__IO uint32_t *)&(REG)) | (BIT); \ } while ((__STREXW(val,(__IO uint32_t *)&(REG))) != 0U); \ } while(0) /* Atomic 32-bit register access macro to clear one or several bits */ #define ATOMIC_CLEAR_BIT(REG, BIT) \ do { \ uint32_t val; \ do { \ val = __LDREXW((__IO uint32_t *)&(REG)) & ~(BIT); \ } while ((__STREXW(val,(__IO uint32_t *)&(REG))) != 0U); \ } while(0) /* Atomic 32-bit register access macro to clear and set one or several bits */ #define ATOMIC_MODIFY_REG(REG, CLEARMSK, SETMASK) \ do { \ uint32_t val; \ do { \ val = (__LDREXW((__IO uint32_t *)&(REG)) & ~(CLEARMSK)) | (SETMASK); \ } while ((__STREXW(val,(__IO uint32_t *)&(REG))) != 0U); \ } while(0) /* Atomic 16-bit register access macro to set one or several bits */ #define ATOMIC_SETH_BIT(REG, BIT) \ do { \ uint16_t val; \ do { \ val = __LDREXH((__IO uint16_t *)&(REG)) | (BIT); \ } while ((__STREXH(val,(__IO uint16_t *)&(REG))) != 0U); \ } while(0) /* Atomic 16-bit register access macro to clear one or several bits */ #define ATOMIC_CLEARH_BIT(REG, BIT) \ do { \ uint16_t val; \ do { \ val = __LDREXH((__IO uint16_t *)&(REG)) & ~(BIT); \ } while ((__STREXH(val,(__IO uint16_t *)&(REG))) != 0U); \ } while(0) /* Atomic 16-bit register access macro to clear and set one or several bits */ #define ATOMIC_MODIFYH_REG(REG, CLEARMSK, SETMASK) \ do { \ uint16_t val; \ do { \ val = (__LDREXH((__IO uint16_t *)&(REG)) & ~(CLEARMSK)) | (SETMASK); \ } while ((__STREXH(val,(__IO uint16_t *)&(REG))) != 0U); \ } while(0) /** * @} */ #if defined (USE_HAL_DRIVER) #include "stm32f1xx_hal.h" #endif /* USE_HAL_DRIVER */ #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* __STM32F1xx_H */ /** * @} */ /** * @} */ stm32f1xx.h
最新发布
07-16
<think>嗯,用户想了解C++中_HAS_CXX17和_HAS_CXX20宏的定义逻辑以及如何根据编译器版本判断这些宏的设置。首先,我需要回忆一下相关的宏和编译器版本对应关系。 根据之前引用的资料,像__cplusplus这样的宏可以检测C++标准的版本。例如,C++17对应的__cplusplus值是201703L,C++20是202002L。但是用户提到的_HAS_CXX17和_HAS_CXX20可能不是标准宏,而是特定编译器(比如MSVC)内部定义的。这需要查证一下。 我记得微软的Visual Studio编译器会有自己的宏定义,比如_HAS_CXX17可能在支持C++17时被定义。而GCC和Clang可能使用不同的方式,比如检查__cplusplus的值。所以首先应该区分不同编译器的处理方式。 对于MSVC来说,_HAS_CXX17和_HAS_CXX20可能由编译器内部根据指定的语言标准版本自动设置。例如,当使用/std:c++17编译时,_HAS_CXX17会被定义为1。但需要确认这些宏是否是MSVC特有的。 对于GCC和Clang,通常使用__cplusplus来判断,比如: #if __cplusplus >= 201703L // C++17或更高 #endif 用户可能需要了解如何在不同编译器中检测C++17和C++20的支持。此外,还要考虑编译器版本,比如GCC 8开始支持C++17完全,GCC 11支持C++20。 还需要提到检查编译器版本的方法,比如使用__GNUC__、__GNUC_MINOR__等宏来判断GCC版本,或_MSC_VER判断MSVC版本,然后结合语言标准宏来确定是否开启特性。 另外,用户可能想知道如何正确设置这些宏,或者项目中的条件编译应该如何编写。例如,在MSVC中,可能需要同时检查_HAS_CXX17和编译器版本,而其他编译器则检查__cplusplus。 需要注意不同编译器的差异,以及如何处理跨平台的情况。可能还需要提到预定义宏的查询方法,比如使用g++ -E -dM来查看GCC定义的宏,帮助用户自行验证。 总结回答的结构应该是:首先解释_HAS_CXXxx宏的用途,然后分编译器讨论设置逻辑,接着说明如何判断编译器版本,最后给出使用示例和注意事项。</think>### C++编译器宏定义逻辑与版本判断解析 #### 一、_HAS_CXX17/_HAS_CXX20宏的核心作用 这两个宏是微软Visual Studio编译器(MSVC)用于标识C++语言版本支持的内部实现机制[^2][^3]。当使用`/std:c++17`或`/std:c++20`编译选项时,编译器会自动定义: ```cpp #define _HAS_CXX17 1 // C++17支持开启 #define _HAS_CXX20 1 // C++20支持开启 ``` 而在其他主流编译器(GCC/Clang)中,通常通过检测`__cplusplus`宏的值来实现版本判断: ```cpp #if __cplusplus >= 201703L // C++17标准值 // C++17代码 #endif ``` #### 二、编译器版本与语言标准对应表 | 编译器 | 版本要求 | C++17支持宏 | C++20支持宏 | |--------|-------------------|----------------------|----------------------| | MSVC | >= VS2017 (v15.7) | _HAS_CXX17=1 | _HAS_CXX20=1(部分) | | GCC | >= 8.0 | __cplusplus=201703L | __cplusplus=202002L | | Clang | >= 7.0 | __cplusplus=201703L | __cplusplus=202002L | #### 三、实现跨平台检测的推荐写法 ```cpp // 检测MSVC的特殊宏 #if defined(_MSC_VER) #if _HAS_CXX20 // MSVC的C++20特性 #elif _HAS_CXX17 // MSVC的C++17特性 #endif #else // 通用编译器检测 #if __cplusplus >= 202002L // C++20特性 #elif __cplusplus >= 201703L // C++17特性 #endif #endif ``` #### 四、编译器版本判断技巧 1. **MSVC版本检测** `_MSC_VER`宏直接对应版本号: ```cpp #if _MSC_VER >= 1930 // VS2022 #elif _MSC_VER >= 1920 // VS2019 #endif ``` 2. **GCC版本检测** 使用`__GNUC__`和`__GNUC_MINOR__`: ```cpp #if __GNUC__ > 8 || (__GNUC__ == 8 && __GNUC_MINOR__ >= 1) // GCC >=8.1 #endif ``` 3. **Clang版本检测** 通过`__clang_major__`判断: ```cpp #if __clang_major__ >= 10 // Clang >=10.0 #endif ``` #### 五、验证宏定义的方法 通过编译器命令查看所有预定义宏: ```bash # GCC/Clang g++ -E -dM - < /dev/null | grep _HAS_CXX # MSVC (开发者命令提示符) cl /B1 "NUL" /E /dD | findstr _HAS_CXX ``` #### 六、实际应用场景 1. **条件编译头文件** ```cpp #if _HAS_CXX17 || __cplusplus >= 201703L #include <filesystem> #else #include <experimental/filesystem> #endif ``` 2. **特性回退实现** ```cpp #if !_HAS_CXX17 && __cplusplus < 201703L // 实现C++14版本的函数 #else // 使用C++17标准库 #endif ``` [^1]: 编译器宏定义与ABI版本控制密切相关 [^2]: MSVC通过_HAS_CXXxx宏管理标准库特性 [^3]: 不同编译器使用不同的版本标识方案 [^4]: 新语言特性往往伴随宏定义变更 [^5]: 宏定义错误可能导致编译行为异常
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值