这是C语言中高级相关知识,在单片机中实战的一些用法
参考C语言江科大视频的学习笔记,详细举例子并且完整记录up的想法,包括内容有c语言数据类型&宏定义#define&关键字typedef&结构体&预处理指令
关键字 | 位数 | 表示范围 | stdint关键字 | ST关键字 |
---|---|---|---|---|
char | 8 | -127-128 | int_8 | s8 |
unsigned char | 8 | 0-255 | uint8_t | u8 |
short | 16 | -32768~32767 | int16_t | s16 |
unsigned short | 16 | 0~65535 | uint16_t | u16 |
int | 32 | -2147483648~2147483647 | int32_t | s32 |
unsigned int | 32 | 0~4294967295 | uint32_t | u32 |
long | 32 | -2147483648~2147483647 | ||
unsigned long | 32 | 0~4294967295 | ||
long long | 64 | -(2^ 64)/2~(2^64)/2-1 | int64_t | |
unsigned long long | 64 | 0~(2^64)-1 | uint64_t | |
float | 32 | -3.4e38~3.4e38 | ||
double | 64 | -1.7e308 ~ 1.7e308 |
- 51单片机中int型为16位;stm32中int型为32位。
- 倒数第二列是C语言给这些类型提供的别名;所以最后一列是老版本ST公司库函数给这些类型提供的别名,新版的库函数已经全部替换成倒数第二列。所以以后尽量使用倒数第二列。
关键字#define,主要用于:用一个字符串代替一个数字,便于理解,防止出错;或者提取程序中经常出现的参数,便于快速修改。俗称叫外号。
//定义宏定义:
#define ABC 12345
//引用宏定义:
int a = ABC;//相当于int a = 12345;
相当于GPIO_InitStructure.GPIO_Pin = ((uint16_t) 0x1000)经过宏定义变成GPIO_InitStructure.GPIO_Pin =GPIO_Pin_12;
在C里面,宏定义定义在主函数外面,并且如果给一个变量宏定义一个值,那么程序里面出这个变量都是这个值,并且是不可修改的
关键字typedef,目的将一个比较长的变量类型名换个比较短的变量类型名,便于使用。
因为结构体变量类型较长,所以通常用typedef更改变量类型名。
//定义typedef:
typedef unsigned char uint8_t;
//引用typedef:
uint8_t num1; //等效于unsigned char num1;
关键字 struct ,用途:数据打包,是不同类型变量的集合。
- struct c;//一个叫做c的结构体里面有{}
- struct {char x;int y;float z;}; c; //一个叫做c的结构体里面有{char x;int y;float z;}
//在main函数中定义结构体变量:
struct{ //相当于struct{ int a;} StructName;
char x;
int y;
float z;
}StructName1;
//因为结构体变量类型(结构体也是一个变量类型)较长,
//所以通常在mian函数外用typedef更改变量类型名
typedef struct{ //相当于(typedef A a),我把长的变量类型A变为短的变量类型a
char x;
int y;
float z;
}StructName_t; //相当于(typedef struct{} StructName_t),
//我把长的变量类型名字struct{}变为短的变量类型名字StructName_t
//引用结构体成员:方法一用‘.’
StructName_t struct1;//我把长的变量类型名字struct{}变为短的变量类型名字StructName_t
//相当于数据类型+变量名字 int a;
struct1.x='A';
struct1.y = 66;
struct1.z = 1.23;
//引用结构体成员:方法二“->”
pStructName ->x = 'A'; //结构体指针名,pStructName为结构体的地址
pStructName ->y = 66;
pStructNmae ->z = 1.23;
关键字enum,enumerate枚举
用途:定义一个取值 受限制的整型变量,也用于限制变量取值范围;
枚举也相当于一个宏定义的集合,可以直接把里面的枚举变量拿出来用。注意枚举变量用逗号隔开,且最后一个枚举变量不加逗号。
//函数内定义枚举变量:
enum{ //enum {} EnumName;
FALSE = 0,
TRUE = 1
}EnumName;
//因为枚举变量类型较长,所以通常在函数外用typedef更改变量类型名
typedef enum{
FALSE = 0;
TRUE = 1
}EnumName;
//引用枚举成员:
EnumName emu1;
emu1 = FLASE;
emu1 = TRUE;
下图的图一和图二是等价的
#ifndef、#define 和 #endif 来确保头文件只被编译一次。
#ifndef __DELAY_H //这是预处理指令,用来判断某个宏是否已经定义,如果该宏(没有)定义,则执行下面的代码
#define __DELAY_H //宏定义
void Delay_us(uint32_t us);
void Delay_ms(uint32_t ms);
void Delay_s(uint32_t s);
#endif
当一个头文件(例如delay.h)被多个源文件引用时,可以使用预处理指令 #ifndef、#define 和 #endif 来确保头文件只被编译一次。
#ifndef 预处理指令:
#ifndef 是 “if not defined” 的简写。
#ifndef 用于检查某个宏是否未定义。如果该宏未定义,则执行下面的代码。
如果宏已经定义过了,#ifndef 中的代码将被忽略。
举例子说明:
#endif
是C/C++中的预处理指令,用于结束条件编译块。
当在代码中使用
#ifdef
、#ifndef
或#if
这些条件编译指令时,需要使用#endif
来标记条件编译块的结束位置。例如,以下是一个简单的条件编译示例:
#ifdef DEBUG_MODE // 调试模式下执行的代码 printf("Debug mode is enabled.\n"); #else // 正常模式下执行的代码 printf("Debug mode is disabled.\n"); #endif 在这个示例中, #ifdef DEBUG_MODE 判断是否定义了 DEBUG_MODE 宏。如果定义了该宏,则执行调试模式下的代码;否则,执行正常模式下的代码。 最后的 #endif 指令用于标记条件编译块的结束位置。它表示上面的条件编译块已经结束,之后的代码将会被正常编译。 总结来说, #endif 用于结束条件编译块,它与 #ifdef 、 #ifndef 或 #if 一起使用,确保条件编译的范围正确闭合。
参考:B站STM32江协自动化&【哈工大虎慕】