stdint.h 简介
stdint.h 是从 C99 中引进的一个标准 C 库的文件. 路径: “D:\MDK5.34\ARM\ARMCC\include”
位操作
运算符 | 含义 | 运算符 | 含义 |
---|---|---|---|
& | 按位与 | ~ | 按位取反 |
| | 按位或 | << | 左移 |
^ | 按位异或 | >> | 右移 |
按位与:
num1 | 运算符 | num2 | 结果 |
---|---|---|---|
0 | & | 0 | 0 |
1 | & | 0 | 0 |
0 | & | 1 | 0 |
1 | & | 1 | 1 |
按位或:
num1 | 运算符 | num2 | 结果 |
---|---|---|---|
0 | | | 0 | 0 |
1 | | | 0 | 1 |
0 | | | 1 | 1 |
1 | | | 1 | 1 |
按位异或:
num1 | 运算符 | num2 | 结果 |
---|---|---|---|
0 | ^ | 0 | 0 |
1 | ^ | 0 | 1 |
0 | ^ | 1 | 1 |
1 | ^ | 1 | 0 |
按位取反:
num | 运算符 | 结果 |
---|---|---|
1001 | ~ | 0110 |
1100 | ~ | 0011 |
1010 | ~ | 0101 |
1111 | ~ | 0000 |
左移:
num | 运算符 | 结果 |
---|---|---|
10110011 | <<2 | 11001100 |
11010010 | <<3 | 10010000 |
10001010 | <<4 | 10100000 |
右移:
num | 运算符 | 结果 |
---|---|---|
10110011 | >>2 | 00101100 |
11010010 | >>3 | 00011010 |
10001010 | >>4 | 00001000 |
寄存器位赋值
uint32_t temp = 0;
给位 6 赋值为 0:
- temp &= 0xFFFFFFBF;
- temp &= ~(1<<6);
给位 6 赋值位 0:
- temp |= 0x00000010;
- temp |= 1>>6;
按位异或翻转位 6:
- temp ^= 0x00000010;
- temp ^=1<<6;
宏定义
宏定义可以: 提高效率, 可读性, 易改性, 核心是替换.
格式:
#define 标识符 字符串
- 标识符: 宏定义的名字
- 字符串: 常数, 表达式, 格式串等
例子:
#define PI 3.1415926
#define HSE_VALUE 8000000U
带参数的宏定义
#define LED1(x) do{ x?\
HAL_GPIO_WritePin(LED1_GPIO_PORT, LED1_GPIO_PIN, GPIO_PIN_SET):\
HAL_GPIO_WritePin(LED1_GPIO_PORT, LED1_GPIO_PIN, GPIO_PIN_RESET);\
}while(0)
建议大家使用 do{…}while(0) 来构造宏定义, 这样不会受到大括号, 分号, 运算符优先级等的影响, 总是会按照你期望的方式调用运行.
例子:
// 定义
#define foo(x) bar(x); baz(x)
// 调用
foo(wolf);
// 宏扩展为
bar(wolf); baz(wolf);
条件编译
让编译器只对满足条件的代码进行编译, 不满足条件的不参与编译!
指令 | 作用 |
---|---|
#if | 编译预处理条件指令, 类似 if |
#ifdef | 判断某个宏是否已被定义 |
#ifndef | 判断某个宏是否未被定义 |
#elif | 若前面的条件不满足, 则判定新的条件, 类似 else if |
#else | 若前面的件不满足, 则执行后面的语句, 类似 else |
#endif | #if, #ifdef, #ifndef的结束标志 |
头文件编译
#ifndef _LED_H
#define _LED_H
#include "./SYSTEM/sys/sys.h"
code
#endif
代码条件编译
#if SYS_SUPPORT_OS
code
#endif
extern 声明
放在函数 / 变量前, 表示此函数 / 变量在其他文件定义, 以便文件引用.
extern unit16_tg_usart_rx_sta;
extern void delay_us(unit32_t nus);
类别名 (typedef)
为现有数据类型创建一个新的名字, 或称为类型别名, 用来简化变量的定义.
格式:
typedef 现有类型 新名字
例子:
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
类型别名应用:
Struct GPIO_TypeDef
{
_IO uint32_t CRL;
_IO uint32_t CRH;
...
};
Struct GPIO_TypeDef gpiox
typedef struct
{
__IO uint32_t CRL;
__IO uint32_t CRH;
...
}GPIO_TypeDef;
GPIO_TypeDef gpiox
结构体
由若干基本数据类型集合组成的一种自定义数据类型, 也叫聚合类型.
格式:
struct 结构体名
{
成员列表;
}变量名列表(可选);
例子:
struct student
{
char *name; // 姓名
int num; // 学号
int age; // 年龄
char group; // 所在学习小组
float score; // 成绩
};
创建学生变量:
struct student student;
student.name = "我是小白呀";
student.num = 1;
student.age = 18;
student.group = "A";
student.score = 99;
应用举例 (ST 源码, 使用类型别名)
typedef struct
{
uint32_t Pin; // 引脚号
uint32_t Mode; // 工作模式
uint32_t Pull; // 上下拉
uint32_t Speed; // IO 速度
}GPIO_InitTypeDef;
指针
指针就是内存的地址, 指针变量是保存了指针的变量.
格式:
类型名 *指针变量名
例子:
char *p_str = "This is a test";
- *p_str: 取 p_str 变量的值
- &p_str: 取 p_str 变量的地址
指针使用的常见问题
- 未分配内存就使用 (野指针)
- 越界使用
错误用法1 (未分配内存):
char *p_buf;
p_buf[0] = 100;
p_buf[1] = 200;
p_buf[2] = 300;
错误用法2 (越界使用):文章来源:https://www.toymoban.com/news/detail-537388.html
uint9_t buf[5] = {1, 2, 3, 4, 5};
uint8_t *p_buf = buf;
p_buf[5] = 200;
p_buf[6] = 250;
代码规范
- 所有函数/变量名字非特殊情况, 一般使用小写字母
- 注释风格使用 doxgen 风格, 除屏蔽外, 一律使用
/* */
方式进行注释 - TAP 键同意使用 4 个空格对其, 不使用默认的方式进行对齐
- 每两个函数之间, 一般有且只有一个空行
- 相对独立的程序块之间, 使用一个空行隔开
- 全局变量命一般用
g_
开头, 全局指针命名一般用p_
开头 -
if, for, while, do, case, switch, default
等语句单独占一行, 一般无论有多少执行语句, 都要用加括号{}
出处: 笔记摘自正点原子文章来源地址https://www.toymoban.com/news/detail-537388.html
到了这里,关于【STM32】基础知识 第五课 C 语言基础知识的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!