嵌入式科普(19)typedef与#define的区别和典型应用

目录

一、概述

二、typedef与#define的区别

2.1. 作用域

2.2. 类型检查

2.3. 参数化

2.4. 调试和可读性

2.5. 宏展开的时间

三、#define 等其他预处理指令

3.1 #include:

3.2 #undef:

3.3 条件编译:

3.4 #pragma:

3.5 #error 和 #warning:

3.6 #line:

3.7 #(字符串化操作符)和 ##(连接操作符):

3.8 预定义的宏:

3.9 内联函数(Inline Functions):

3.10 constexpr(C++11 及更高版本):

3.11 enum class(C++11 及更高版本):

四、typedef与#define的典型应用


嵌入式科普(19)typedef与#define的区别和典型应用

一、概述

  • 介绍typedef与#define的区别

  • 介绍其他预处理指令指令

  • typedef与#define的典型应用

二、typedef与#define的区别

2.1. 作用域

#define:

#define定义的宏没有作用域限制,一旦定义,在整个源文件中都有效(如果使用了头文件,则在所有包含该头文件的文件中都有效)。
例子:

#define PI 3.14159

在这个例子中,PI被定义为一个宏,在整个文件中都可以使用PI来代表3.14159。

typedef:

typedef定义的别名有作用域限制,通常遵循C/C++的变量和函数的作用域规则。
例子:

typedef int Integer;  
  
void foo() {  
    Integer i = 10; // 有效  
}  
  
int main() {  
    Integer j = 20; // 有效  
    return 0;  
}

在这个例子中,Integer是int的一个别名,它仅在定义它的文件或作用域中有效。

2.2. 类型检查

#define:

#define仅仅是文本替换,没有类型检查。如果替换后的文本不符合预期的类型,编译器在编译时可能会产生错误,但错误可能很难理解,因为问题可能来源于宏展开后的代码。
例子:

#define MULTIPLY(x, y) ((x) * (y))  
  
int main() {  
    int a = 5, b = 10;  
    int c = MULTIPLY(a, b); // 正确  
    int d = MULTIPLY(a, "hello"); // 错误,但错误可能不容易理解  
    return 0;  
}

在这个例子中,尝试将字符串与整数相乘会导致编译错误,但由于是宏替换,错误可能不容易追踪。

typedef:

typedef创建的别名是类型安全的,因为它们是基于现有类型的。
例子(与typedef本身无关,但为了展示类型安全性):

typedef int Integer;  
  
void add(Integer a, Integer b) {  
    // ...  
}  
  
int main() {  
    Integer i = 10;  
    char c = 'a';  
    add(i, c); // 错误,因为c不是Integer类型  
    return 0;  
}

在这个例子中,尝试将char类型的变量传递给期望Integer(即int)类型的函数会导致编译错误。

2.3. 参数化

#define:

#define可以定义带参数的宏,实现更复杂的文本替换。
例子(如上面的MULTIPLY宏所示)。

typedef:

typedef不能定义带参数的别名。它只能为现有类型创建简单的别名。

2.4. 调试和可读性

#define:

由于#define只是文本替换,因此在调试时可能更难追踪和理解代码的行为。
typedef:

typedef创建的别名是类型安全的,并且在调试时更易于理解,因为它们是基于现有类型的。

2.5. 宏展开的时间

#define:

宏在预处理阶段展开,即在编译器开始真正的编译工作之前。
typedef:

typedef在编译阶段处理,它创建的别名是编译器可以理解的类型。

三、#define 等其他预处理指令

3.1 #include:

用于包含(或插入)其他文件的内容。
有两种形式:#include(用于标准库)和 #include "filename"(用于项目中的文件)。

3.2 #undef:

用于取消(或删除)先前由 #define 定义的宏。

3.3 条件编译:

#if, #ifdef, #ifndef, #elif, #else, #endif
这些指令允许你根据某些条件(通常是宏的定义)来选择性地编译代码块。

3.4 #pragma:

这是一个特定于编译器的指令,用于提供编译器特定的指令或选项。
例如,在Microsoft的编译器中,#pragma once 用于确保头文件只被包含一次。

3.5 #error 和 #warning:

#error 指令在预处理阶段生成一个错误消息,并停止编译。
#warning 指令生成一个警告消息,但编译过程会继续。

3.6 #line:

用于改变编译器报告的当前行号和文件名。

3.7 #(字符串化操作符)和 ##(连接操作符):

这两个操作符在宏定义中很有用。# 操作符可以将宏参数转换为字符串,而 ## 操作符可以用于连接两个标记以形成一个新的标记。

3.8 预定义的宏:

编译器提供了一些预定义的宏,如 LINE(当前行号)、FILE(当前文件名)、DATE(编译日期)和 TIME(编译时间)等。

3.9 内联函数(Inline Functions):

虽然不是预处理指令,但内联函数在某些方面与宏类似,因为它们都在编译时展开,以减少函数调用的开销。然而,内联函数是函数,因此它们具有作用域、类型检查和参数检查等特性。

3.10 constexpr(C++11 及更高版本):

constexpr 关键字用于在编译时计算常量表达式的值。虽然它与 #define 不同,但在某些情况下,它可以作为 #define 的一个更安全、更类型安全的替代方案。

3.11 enum class(C++11 及更高版本):

enum class(也称为强类型枚举或作用域枚举)提供了一种比传统 enum 更安全、更类型安全的方式来定义常量集。虽然它们不是预处理指令,但在某些情况下,它们可以作为 #define 的一个替代方案。

四、typedef与#define的典型应用

/** Blocks execution */
#define STM32_LOCK_BLOCK()                      \
  do                                            \
  {                                             \
    __disable_irq();                            \
    Error_Handler();                            \
    while (1);                                  \
  } while (0)
#define SQUARE(x) ((x) * (x))
#define DEBUG 1  
  
#if DEBUG  
#define PRINT_DEBUG(x) printf("Debug: %s\n", x)  
#else  
#define PRINT_DEBUG(x)  
#endif
/*******************************************************************************************************************//**
 * Enables the module stop state.
 *
 * @param      ip       fsp_ip_t enum value for the module to be stopped
 * @param      channel  The channel. Use channel 0 for modules without channels.
 **********************************************************************************************************************/
#define R_BSP_MODULE_STOP(ip, channel)             {FSP_CRITICAL_SECTION_DEFINE;                                  \
                                                    FSP_CRITICAL_SECTION_ENTER;                                   \
                                                    BSP_MSTP_REG_ ## ip(channel) |= BSP_MSTP_BIT_ ## ip(channel); \
                                                    BSP_MSTP_REG_ ## ip(channel);                                 \
                                                    FSP_CRITICAL_SECTION_EXIT;}
#ifndef   __ASM
  #define __ASM                                  __asm
#endif
#ifndef   __INLINE
  #define __INLINE                               inline
#endif
#ifndef   __STATIC_INLINE
  #define __STATIC_INLINE                        static inline
#endif
#ifndef   __STATIC_FORCEINLINE                 
  #define __STATIC_FORCEINLINE                   __attribute__((always_inline)) static inline
#endif                                           
#ifndef   __NO_RETURN
  #define __NO_RETURN                            __attribute__((__noreturn__))
#endif
#ifndef   __USED
  #define __USED                                 __attribute__((used))
#endif
#ifndef   __WEAK
  #define __WEAK                                 __attribute__((weak))
#endif
#ifndef   __PACKED
  #define __PACKED                               __attribute__((packed, aligned(1)))
#endif
#ifndef   __PACKED_STRUCT
  #define __PACKED_STRUCT                        struct __attribute__((packed, aligned(1)))
#endif
#ifndef   __PACKED_UNION
  #define __PACKED_UNION                         union __attribute__((packed, aligned(1)))
#endif

typedef __uint32_t uint32_t ;

typedef MyType *MyTypePtr;

typedef struct _s_pns_nv_subcfg TS_PNS_NV_SUBCFG, *TS_PNS_NV_SUBCFG_PTR;

图片

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值