typedef char* var 和 #define var char * 的区别

本文探讨了C语言中typedef与#define的用法差异。主要分析了二者在类型检查、变量声明等方面的不同,并强调了typedef相比#define具备更高的安全性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • typedef char * String_t 定义了一个新的类型别名,有类型检查。
    #define String_d char * 只做了简单的替换,无类型检查。
  • 前者在编译的时候处理,后者在预编译的时候处理。
  • 同时定义多个变量的时候有区别,主要区别在于这种使用方式:
    String_t a,b; String_d c,d;
    a,b,c 都是char *类型,而d为char类型
  • 由于typedef 还要做类型检查,#define 没有,所以typedef 比#define 安全

转自:http://blog.youkuaiyun.com/sinat_29844779/article/details/61191501

#ifndef __SYS_H__ #define __SYS_H__ #include "t5los8051.h" #include <string.h> typedef unsigned char u8; typedef unsigned short u16; typedef unsigned long u32; typedef char s8; typedef short s16; typedef long s32; //宏定义 #define WDT_ON() MUX_SEL|=0x02 /******开启看门狗*********/ #define WDT_OFF() MUX_SEL&=0xFD /******关闭看门狗*********/ #define WDT_RST() MUX_SEL|=0x01 /******喂狗*********/ #define FOSC 206438400UL #define T0MS 48333 //(65536-FOSC/12/1000)//1ms //48333////1ms #define T2MS 48333 //(65536-FOSC/12/1000) #define NULL ((void *)0) #define TIMER_NUMBER 8 //#define TimeOutSet2 10 #define UART2_TX_LEN 256 #define UART2_RX_LEN 1024 #define UART3_TX_LEN 256 #define UART3_RX_LEN 1024 #define UART4_TX_LEN 256 #define UART4_RX_LEN 1024 #define UART5_TX_LEN 256 #define UART5_RX_LEN 1024 #define UART_FRM_LEN 264 typedef struct Uart_Type_t{ u8 id; //串口号 u16 Tx_Read; //发送读指针 u16 Tx_Write; //发送写指针 u8 Tx_Busy; //发送忙 u16 Rx_Read; //接收读指针 u16 Rx_Write; //接收写指针 u8 Rx_Busy; //接收忙 u8 Rx_Flag; //接收标志 u8 Rx_Buffer[UART2_RX_LEN]; //接收缓冲 u8 Tx_Buffer[UART2_TX_LEN]; //发送缓冲 } *P_S_UART; extern struct Uart_Type_t Uart2; typedef struct UartFrameData{ u8 dataLen; //接收的数据长度 u8 dataCode; //操作代码 u16 varAddr; //变量地址 u8 varData[UART_FRM_LEN];//变量数据 u8 varIndex; //变量数据指针 } *P_D_UART; extern void ResetFrame(P_S_UART Uart_number, P_D_UART Uart_data); void INIT_CPU(void); void page_change(u16 Page); //切页 u16 get_ad_value(u16 adIdx); //ad配置 void pwm_init(u8 id); //pwm初始化配置 void pwm_set(u16 Pec,u8 id);//pwm配置占空比 #endif #include "bsp_uart4.h" #if UART4_ENABLE struct Uart_Type_t Uart4; /***************************************************************************** 函 数 名 : void Uart4_Init(u32 baud_rate) 功能描述 : 串口4初始化 输入参数 : baud_rate 波特率 输出参数 : 修改历史 : 1.日 期 : 2022年3月9日 作 者 : LYN 修 改 : cuijia *****************************************************************************/ void Uart4_Init(const u32 baud_rate) { u16 i, baud; Uart4.id = 2; Uart4.Tx_Read = 0; Uart4.Tx_Write = 0; Uart4.Tx_Busy = 0; Uart4.Rx_Read = 0; Uart4.Rx_Write = 0; Uart4.Rx_Busy = 0; Uart4.Rx_Flag = 0; for(i = 0; i < UART4_TX_LEN; i++){ Uart4.Tx_Buffer[i] = 0; } for(i = 0; i < UART4_RX_LEN; i++){ Uart4.Rx_Buffer[i] = 0; } P0MDOUT |= 0x03; //P0口输出配置 SCON2T= 0x80 ; //发送使能模式设置 SCON2R= 0x80; //接受使能模式设置 ES2R = 1; //中断接受使能 ES2T = 1; //中断发送使能 baud = FOSC/8.0/baud_rate; BODE2_DIV_H = (u8)(baud>>8);//波特率 = CPU 主频/(8*波特率) BODE2_DIV_L = (u8)baud; // P0MDOUT|=(1<<0); //p0^0 强推 TR4 = 0; EA = 1; //中断总控制位:中断是否打开由每个中断的控制位控制。 } /************************************************** 函 数 名 : void Uart4_Tx_write2buff(u8 dat) 功能描述 : 装载串口4发送缓冲 输入参数 : dat:预发送的数据 输出参数 : 修改历史 : 1.日 期 : 2022年3月9日 作 者 : LYN 修改内容 : 创建 ***************************************************/ void Uart4_Tx_write2buff(u8 dat) { /*装发送缓冲*/ Uart4.Tx_Buffer[Uart4.Tx_Write] = dat; /*缓冲队列写指针回头,读指针在前*/ if(Uart4.Tx_Read > Uart4.Tx_Write) { /*若缓冲区满,等待读指针前进*/ while((Uart4.Tx_Write) + 1 == Uart4.Tx_Read); } /*写指针前进*/ ++Uart4.Tx_Write; /*写指针即将回头*/ if(Uart4.Tx_Write >= UART4_TX_LEN) { /*若读指针在头,等待读指针前进*/ while(Uart4.Tx_Read == 0); /*写指针回头*/ Uart4.Tx_Write = 0; } /*空闲*/ if(Uart4.Tx_Busy == 0) { /*标志忙*/ Uart4.Tx_Busy = 1; /*485开启发送*/ TR4=1; /*触发发送中断*/ SCON2T |= 0x1; } } /**************************************************************************** * * 函 数 名 : void Uart4_RX_ISR_PC(void) interrupt 11 * 功能描述 : 串口 4中断接收函数 * 输入参数 : * 输出参数 : * *****************************************************************************/ void Uart4_RX_ISR_PC(void) interrupt 11 { EA = 0; //中断总控制位;所有中断关闭 SCON2R &= 0xFE; Uart4.Rx_Buffer[Uart4.Rx_Write] = SBUF2_RX; Uart4.Rx_Write++; Uart4.Rx_Write %= UART4_RX_LEN; EA = 1; //中断总控制位;中断是否打开由每个中断的控制位控制。 } /**************************************************************************** * * 函 数 名 : Uart4_TX_ISR_PC(void) interrupt 10 * 功能描述 : 串口 4中断发送函数 * 输入参数 : * 输出参数 : * ******************************************************************************/ void Uart4_TX_ISR_PC(void) interrupt 10 { EA = 0; //中断总控制位;所有中断关闭 SCON2T &= 0xFE ; if(Uart4.Tx_Read != Uart4.Tx_Write) { SBUF2_TX = Uart4.Tx_Buffer[Uart4.Tx_Read]; Uart4.Tx_Read++; Uart4.Tx_Read %= UART4_TX_LEN; } else { /*485关闭发送*/ TR4 = 0; Uart4.Tx_Busy = 0; } EA = 1; //中断总控制位;中断是否打开由每个中断的控制位控制。 } #endif 用C51语言,使用UART4串口,实现DMG10600T101_01WTR屏进行RS232通信,结合上述程序写一个详细代码注释
最新发布
07-11
<think>我们正在处理一个关于C语言宏定义的问题。用户询问`#define uint8_t unsigned char`报错的原因及解决方法。 首先,我们需要分析可能的原因: 1. **重复定义**:`uint8_t`是C99标准中在`stdint.h`头文件中定义的类型。如果用户包含了`stdint.h`又试图用宏重新定义,就会导致重复定义错误。 2. **宏定义的位置问题**:宏定义必须在所有使用之前,且不能放在函数内部。如果放在函数内部,那么该宏的作用域仅限于该函数,在函数外部使用会导致未定义错误。 3. **宏定义中的语法错误**:虽然这个宏看起来很简单,但也要注意是否有额外的空格或其他不可见字符导致问题。 4. **宏定义与现有标识符冲突**:除了标准库中的定义,如果用户自己定义了`uint8_t`变量或函数,再使用这个宏也会导致冲突。 根据引用[1][2]的内容,我们知道`#define`只是简单的文本替换,而且它`typedef`有本质区别。在引用[1]中特别指出,用`#define`定义指针类型时可能会导致问题,但这里定义的是非指针类型,所以指针问题不适用。 但是,引用[2]提到`typedef``#define`的区别,其中特别指出`typedef`定义的是类型,而`#define`可以定义类型别名,但要注意作用域替换规则。 因此,我们重点考虑重复定义的问题。因为`uint8_t`是标准类型,通常我们不应该重新定义它。如果用户没有包含`stdint.h`,那么这样定义可能不会报错,但一旦包含就会冲突。 解决方法: 1. **避免重新定义**:使用标准头文件`<stdint.h>`,而不是自己定义`uint8_t`。 2. **检查是否已包含头文件**:如果用户已经包含了`stdint.h`,那么删除这个宏定义。 3. **使用条件编译**:如果确实需要自定义(例如在特定的平台上),可以使用条件编译来避免重复定义。例如: ```c #ifndef uint8_t #define uint8_t unsigned char #endif ``` 但是,这种方法仍然有风险,因为标准库中已经定义了`uint8_t`,所以条件编译可能无法覆盖(因为标准库头文件中已经定义了,所以`uint8_t`已经被定义)。 4. **使用`typedef`代替**:虽然`typedef`也不能重复定义,但至少可以避免一些宏替换的问题。不过,同样存在与标准库冲突的问题。 因此,最佳实践是使用标准库,避免自己定义。 另外,如果用户是在C++环境中使用C语言代码,也要注意C++对类型的要求更严格,可能会报错。 总结步骤: 1. 检查是否包含了`stdint.h`,如果已经包含,则删除自己的宏定义。 2. 如果没有包含`stdint.h`,但需要标准类型,则包含`stdint.h`并删除自己的宏定义。 3. 如果用户处于特殊环境(如嵌入式系统没有标准库),那么可以自定义,但要确保在整个项目中保持一致,并且使用条件编译防止重复定义。 现在,我们按照要求组织回答: - 使用中文回答。 - 结构清晰,分步骤说明。 - 生成相关问题。 注意:引用标记要自然地添加在引用内容的末尾。</think>### `#define uint8_t unsigned char` 报错原因及解决方法 #### 错误原因分析 1. **与标准库冲突** `uint8_t` 是 C99 标准在 `<stdint.h>` 头文件中明确定义的类型(8位无符号整数)。如果代码中已包含 `<stdint.h>` 或类似头文件(如 `<inttypes.h>`),再使用 `#define` 重定义会导致类型冲突。 **错误示例**: ```c #include <stdint.h> #define uint8_t unsigned char // 冲突!stdint.h 已定义 uint8_t ``` [^1] 2. **宏定义作用域问题** `#define` 是预处理指令,在编译前进行**文本替换**。若宏定义在局部作用域(如函数内),外部无法访问;若在全局作用域但未包含头文件,可能导致未定义错误: ```c void func() { #define uint8_t unsigned char // 仅在此函数内有效 } uint8_t var; // 外部报错:未定义标识符 ``` 3. **宏替换的副作用** 引用[1]指出,`#define` 是简单的文本替换,而 `typedef` 是类型定义。例如: ```c #define uint8_ptr unsigned char* uint8_ptr a, b; // 实际展开为: unsigned char* a, b; → b 是普通 char 类型! ``` 此处 `b` 会被错误定义为 `char` 而非指针,而 `uint8_t` 定义虽无此问题,但原理相同[^1][^2]。 --- #### 解决方案 1. **优先使用标准库** 直接包含 `<stdint.h>` 并调用标准类型: ```c #include <stdint.h> uint8_t var = 0; // 正确使用标准类型 ``` 2. **检查宏定义位置** 确保宏定义在全局作用域且**早于所有使用位置**: ```c #define MY_UINT8 unsigned char // 自定义别名(避免与标准库冲突) // 后续使用 MY_UINT8 ``` 3. **使用 `typedef` 替代(推荐)** 引用[2]强调,`typedef` 能正确定义类型别名,避免宏替换的副作用: ```c typedef unsigned char my_uint8; // 正确定义类型 my_uint8 a, b; // a b 均为 unsigned char ``` 4. **条件编译(特殊场景)** 若需兼容无 `<stdint.h>` 的环境(如旧编译器),可添加保护: ```c #ifndef uint8_t #define uint8_t unsigned char #endif ``` --- #### 关键区别:`#define` vs `typedef` | 特性 | `#define` | `typedef` | |--------------------|-------------------------------|-------------------------------| | 本质 | 预处理文本替换 | 编译器识别的类型别名 | | 作用域 | 无作用域,全局替换 | 遵守作用域规则 | | 指针定义安全性 | 易出错(如 `#define PTR int*`)| 安全(`typedef int* PTR;`) | | 类型检查 | 无(替换后检查) | 有(编译时检查) | [^1][^2] > **最佳实践**:除非有特殊需求,否则**避免重定义标准类型**。优先使用 `<stdint.h>` 中的 `uint8_t`,或用 `typedef` 创建自定义类型别名。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值