目录
关键字
常用数据类型(char int float)
- typedef 为取别名关键字
- 在项目中常使用typedef将冗长的数据类型关键字替换为简短的表达形式
常用构造数据类型(enum struct)
- enum 枚举类型关键字(enum与struct本质与int是相同的皆用于声明变量的类型)
- 其中第一个元素对应值默认为0,欲使其为其他数值可以设置第一个元素为“=1或其他数值”,后续元素将会自动递增1。
- 其元素基本类型为unsigned int
- 为了赋予其实际意义,常与typedef共同使用,以下为一种常用的声明方式,使用gimbal_motor_mode_e 即为该列表的对象
- 关于“对象”与其实例化,本为基于c语言开发的其他语言概念如C++,python。可以理解为对象为“哺乳动物”,其实例化为“人类”。
- gimbal_motor_mode_e 为对象,gimbal_motor_mode与last_gimbal_motor_mode为其实例化,分别使用独立的存储空间。
- struct 结构体类型关键字(数组:所有元素基本数据类型相同,结构体:每个元素的基本数据类型任意,所以可以在结构里定义枚举类型数据以及结构体类型数据)
- 同样地,也常与typedef一起使用,定义的结构体也是对象需要实例化之后才能正常使用。
- 调用结构体中的元素 "."只需声明结构体即可调用,“->”需声明结构体指针并开辟独立的储存空间才能使用
- ".“一般情况下读作"的”。“->”一般读作"指向的结构体的”
- A->a等效于(*A).a(暂时只做了解,后续指针部分内容将会完整说明)
该图片引用自: C语言中“.”与->的区别 - 底层寄存器常使用指针结构体
__packed
-
struct常用在数据结构中。而struct的字节对齐方式对于嵌入式底层的程序员来讲是必须掌握的。现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐
-
对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些架构的CPU在访问 一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对 数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数 据。显然在读取效率上下降很多。
转载自: C语言中__packed 和位段的理解 -
struct {
char a; //1byte
int b; //4byte
char c[2] //2byte
double d; //8byte
}Struct_A; -
在计算机内存中,结构体变量的存储通常是按字长对齐的,比如8位机里就按字节对齐,那么上述结构体共占用1+4+2+8=15byte。
在16位机里,变量就按照2字节对齐,比如a这个成员,虽然是个char类型,地址在0x80000000本身只占1字节,但是下一个成员b却不能使用0x80000001这个地址,而必须使用0x80000002,这就是按字长对齐。以上结构体占用的空间也就是2+4+2+8=16字节
同理,在32位机中,如果a在0x80000000的话,b只能放在0x80000004,因为这里的字长是4个字节。以上结构体占用空间4+4+4+8=20字节
也就是说总有一些字节是浪费掉的,这样做的目的很简单,就是因为在大多数计算机体系结构中,对内存操作时按整字存取才能达到最高效率,相当于是以空间换取时间。当然在某些计算机体系结构中,比如ARM,是支持非对齐字传输的,也就是说变量并不一定要按照字长对齐,尽管这样可能会降低效率,但换来的是存储空间上的节约。在mdk中加上__packed关键字,可以得到非对齐字的紧凑型结构体,则会强制编译器将结构体成员按1字节对齐,则以上结构体占用空间仍为15字节。
转载自:__packed 关键字 的作用
示例:
static与const
- static 用于声明静态数据类型,在项目中常在,c文件中定义静态函数,则其在其他文件不仅可见(.h),故在其他文件需使用外部引用关键字extern 声明才能使用,在.c定义并在.h中这么声明的好处在于可以节省空间并防止编译出错,以保证该数据只定义一次。
Static使用位置 | 效果 |
---|---|
局部变量 | 改变其生存周期,不改变其作用域(不会在函数结束时销毁) |
全局变量 | 不改变其生存周期,改变其作用域 (只能被本.c文件索引) |
函数 | 不改变其生存周期,改变其作用域 (不可通过.h文件被其他.c文件索引,但可以定义同名函数) |
- 详细内容可参考以下文章: c语言中static关键字用法详解
- const 则用于声明该数据不可外部更改,保证其数据传递的稳定。
常用逻辑结构(if while for)
-
if 条件判断(条件为恒等内容时需使用 “==”而非“=”)
同时宏定义常使用#if #else #endif 进行条件编译
详细内容可参考: #if、#else、#endif、#elif、#ifdef、#ifndef的区别和使用
在.h文件中为避免重复定义,常使用#ifndef #define #endif结构声明该文件的的唯一性(如果没有定义… 则定义… 结束 名字可以随便取但出于规范尽量合理命名)
-
while 循环逻辑,条件满足则死循环直到条件不满足,其衍生结构还有do while
while do(先判断条件在做 先做再判断条件)
for循环逻辑,与while的区别在于可以执行设定次数的循环。
三种循环语句的详解和使用(for,while,do-while)
C语言 while语句的用法
多使用if,非必要不使用while for。- goto 无条件跳转
当项目庞大后goto语句会使得程序整体结构化降低,难以发现错误,但在单个函数内使用不容易出错。
- goto 无条件跳转
#error #warning
- #error 用于自定义一条编译错误信息
- #warning 用于自定义一条编译警告信息
- 示例:
指针
- 指针的作用在于作为一个传递数据的通道
- 声明 数据类型 * p(*与p靠近或与int靠近皆可)
- *p为指针地址所存放内容,p为指针所指地址,&p 该指针存放的地址,**p 套娃指针,存放的的一级指针的地址
- 指针的类型为地址,故再传递的时候需传递地址(指针所指地址 set_mode,结构体地址 &gimbal_control,使用这样的方法即可无需过多声明即可完成数据的传递。
动态内存管理
- void *malloc(size_t size)
向系统申请大小为size的内存空间,返回指向这块空间的函数
配套函数为void free(void *ptr)释放该内存空间,否则会造成内存泄漏
void类型的指针可以赋值给仍和类型的指针
示例:
- void *memset(void *s, int c, size_t n);
使用常量字节 c 填充 s 指向的前 n 个字节。 - void *memcpy(void *dest, const void *src, size_t n);
从 src 指向的内存空间拷贝 n 个字节到 dest 指向的内存空间。src 和 dest 指向的内存区域不能出现重叠,否则应该使用 memmove 函数 - void *memmove(void *dest, const void *src, size_t n);
从 src 指向的内存空间拷贝 n 个字节到 dest 指向的内存空间。