关于学习STM32的C语言的知识
-
数据类型
关键字 | 位数 | 表示范围 | stdint关键字 |
char | 8 | -128 ~ 127 | int8_t |
unsigned char | 8 | 0 ~ 255 | uint8_t |
short | 16 | -32768 ~ 32767 | int16_t |
unsigned short | 16 | 0 ~ 65535 | uint16_t |
int | 32 | -2147483648 ~ 2147483647 | int32_t |
unsigned int | 32 | 0 ~ 429496729 | uint32_t |
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 |
-
宏定义
定义:在C语言中,宏定义是一种预处理指令,用于将一个标识符(宏名)替换为指定的字符串(常数、表达式、格式串等)。这个过程称为“宏展开”或“宏替换”。宏定义是通过使用 #define 预处理命令来完成的。
格式:# define 宏名 字符串
作用:
- 提升易读性:比如 # define HIGH 1
- 便于批量修改:比如 # define PIN 5
应用场景:
- 定义一个常量
# define PI 3.14159
- 宏函数:
C语言的宏定义还支持一些更复杂的操作,如算术运算和逻辑运算。例如:
#define area(x) (x * x)
在这个例子中,我们定义了一个名为 AREA 的宏,它接受一个参数 x ,并返回 x * x 的结果。当程序中出现area(5) 时,它会被替换为 (5 * 5) 。
在stm32中经常和条件运算符结合使用:
#define LED(X) do{x?A:B}while(0);
上面代码中:do-while 语句 经常在stm32中使用。
-
typedef
定义:通过使用 typedef ,可以为现有的 数据类型 创建一个新的名称,这样可以使代码更加简洁、易读。
应用场景:
typedef 可以用于为基本数据类型、结构体、联合体(共用体)等定义别名。
- 可以定义一个名为 SIZE 的类型,该类型为 unsigned int 类型:
typedef unsigned int SIZE;
SIZE a = 10;
a = 20;
- 可以使用 IntPtr 作为指向整数的指针类型的别名:
typedef int* IntPtr;
IntPtr p = malloc(sizeof(int));
*p = 10;
teypdef 与 宏定义的区别(记住):
- 宏定义新名字左边,typedef在右边;
- 宏定义不需要分号,typedef需要分号;
- typedef只能替换数据类型,宏定义一切可以替换;
- typedef具有检查的功能,判断替换的是不是数据类型。
-
条件编译
与C存在区别:需要加上 “# ”号;#elif(C中是elseif);endif 结束。
C语言中的条件编译主要通过 #if 、#ifdef 、#ifndef 、#else 、 #elif 和 #endif 等预处理指令来实现。这些指令可以在代码的任何位置使用,以根据特定的条件来控制代码的编译。
例子1:(#if - #elif - #endif)
#if 表达式1// 如果表达式1为真,则编译下面的代码
#elif 表达式2// 如果表达式1为假且表达式2为真,则编译下面的代码
#else// 如果未定表达式1和表达式2都未执行,则编译此处的代码
#endif
例子2:(# ifdef 和 # ifndef)
#ifdef 宏名//如果宏已经定义,则编译下面的代码
#endif
#ifndef 宏名// 如果宏未定义,则编译下面的代码
#endif
常用于定义一个.h的文件中先声明是否进行宏定义。
-
结构体
struct 结构体名 {数据类型 成员名1;数据类型 成员名2;...数据类型 成员名n;};
举例:在定义结构体后,可以在程序中使用该结构体来声明变量,并为其分配内存空间。
struct Student {char gender;int age;float score;
};
struct Student stu1;
在上面的例子中,我们定义了一个名为 Student 的结构体类型,它包含三个成员: gender 、 age 和 score 。然后我们声明了一个名为 stu1 的结构体变量,并为其分配了内存空间。
结构体变量可以用于存储具有不同属性或特征的数据,例如学生的性别、年龄和成绩。结构体中的成员可以通过点运算符( . )来访问,例如 stu1.name 表示访问 stu1 变量的 name 成员。
此外,C语言还提供了 结构体数组、结构体指针 (详见C文章中的结构那章)等用法,以便更灵活地处理和操作结构体数据
-
枚举 (enum)
应用1:为一组整数值分配有意义的名字。
C语言中的枚举(enum)是一种用户定义的数据类型,它允许你为一组整数值分配有意义的名字。枚举常用于为变量的可能值定义有意义的名称,或者为编译器的内部值分配用户定义的名称。
格式:
enum 枚举名 {
常量1 , 常量 2 , ...};
其中, 枚举名 是你给枚举类型起的名字,而 常量1 、 常量2 等是该枚举类型的成员名。这些成员名在编译时会被赋予整数值,默认从0开始,每次递增1。
举例:
enum Color {
RED=0, GREEN, BLUE
};
在这个例子中,我们定义了一个名为 Color 的枚举类型,它有三个成员: RED 、 GREEN 和 BLUE 。这三个成员在编译时会被赋予整数值,分别是0、1和2。
应用2:限制变量的取值范围。
enum Weekday {
MONDAY=1, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
};enum Weekday today;
today = MONDAY; // 或者其他有效的枚举值
-
指针(具体详见C语言篇章中的指针)
定义:C语言中的指针是一种特殊的变量,它存储了一个内存地址,这个地址可以是其他 变量 的地址,也可以是 数组的元素、结构体、函数等类型的地址。通过指针,我们可以间接地访问和操作这些内存地址所指向的内容。
一些C语言指针的例子:
1.定义并初始化指针
int x = 10;
int *p = &x; // p指向变量x的地址
2.通过指针访问变量
int value = *p; // 获取p所指向的整数值,即x的值
*p = 20; // 修改p所指向的整数值,即x的值
3. 指针的算术运算
int arr[5] = {1, 2, 3, 4, 5};
int *ptr = arr; // ptr指向数组的首地址
int i = 0;
for (i = 0; i < 5; i++) {
printf("%d ", *(ptr + i)); // 输出数组元素的值
}
4. 动态内存分配:
int *p = ( int * )malloc(sizeof( int )); // 分配一个整数的内存空间,返回指向该空间的指针p
if (p != NULL) { //如果内存空间创建成功
*p = 20; // 在该内存空间中存储整数值20
printf("%d\n", *p); // 输出20
free(p); // 释放内存空间
}
但同时也要注意指针的使用可能会导致 内存泄漏、野指针 等问题,需要谨慎处理。