项目需要学习STM32中的一些函数的使用,但其中涉及到许多指针、结构、变量等等,虽然在学校的C语言基础课程中已经学习了一部分,但这一部分过于基础,所以针对性的又学习了算是进阶的知识点,这里主要参考这篇文章,以及学长发的文件中的学习笔记进行针对性的学习
https://www.cnblogs.com/lnleelove/p/9751804.html
与、或、非运算
#ifdef 标识符
程序段1
#else
程序段2
#endif
**它的作用是:**当标识符已经被定义过(一般是用#define命令定义),则对程序段1进行编译,否则编译程序段2。
其中#else部分也可以没有,即:
#ifdef
程序段1
#denif
这里的“程序段”可以是语句组,也可以是命令行。这种条件编译可以提高C源程序的通用性。如果一个C源程序在不同计算机系统上系统上运行,而不
同的计算机又有一定的差异。例如,我们有一个数据类型,在Windows平台中,应该使用long类型表示,而在其他平台应该使用float表示,这样
往往需要对源程序作必要的修改,这就降低了程序的通用性。可以用以下的条件编译:
#ifdef WINDOWS
#define MYTYPE long
#else
#define MYTYPE float
#endif
如果在Windows上编译程序,则可以在程序的开始加上
#define WINDOWS
这样则编译下面的命令行:
#define MYTYPE long
如果在这组条件编译命令之前曾出现以下命令行:
#define WINDOW
则预编译后程序中的MYTYPE都用float代替。这样,源程序可以不必作任何修改就可以用于不同类型的计算机系统。当然以上介绍的只是一种
简单的情况,可以根据此思路设计出其它的条件编译。
例如,在调试程序时,常常希望输出一些所需的信息,而在调试完成后不再输出这些信息。可以在源程序中插入以下的条件编译段:
#ifdef DEBUG
print ("device_open(%p)\n", file);
#endif
如果在它的前面有以下命令行:
#define DEBUG
则在程序运行时输出file指针的值,以便调试分析。调试完成后只需将这个define命令行删除即可。有人可能觉得不用条件编译也可达此目
的,即在调试时加一批printf语句,调试后一一将printf语句删除去。的确,这是可以的。但是,当调试时加的printf语句比较多时,修改的
工作量是很大的。用条件编译,则不必一一删改printf语句,只需删除前面的一条“#define DEBUG”命令即可,这时所有的用DEBUG作
标识符的条件编译段都使其中的printf语句不起作用,即起统一控制的作用,如同一个“开关”一样。
有时也采用下面的形式:
#ifndef 标识符
程序段1
#else
程序段2
#endif
只是第一行与第一种形式不同:将“ifdef”改为“ifndef”。它的作用是:若标识符未被定义则编译程序段1,否则编译程序段2。这种形
式与第一种形式的作用相反。
以上两种形式用法差不多,根据需要任选一种,视方便而定。
typedef为C语言的关键字,作用是为一种数据类型定义一个新名字,这里的数据类型包括内部数据类型(int,char等)和自定义的数据类型(struct等)。
typedef本身是一种存储类的关键字,与auto、extern、static、register等关键字不能出现在同一个表达式中。
使用typedef定义新类型的方法:在传统的变量声明表达式里用(新的)类型名替换变量名,然后把关键字typedef加在该语句的开头就行了。
下面以两个示例,描述typedef的用法步骤。
示例1:
int a; ———— 传统变量声明表达式
int myint_t; ———— 使用新的类型名myint_t替换变量名a
typedef int myint_t; ———— 在语句开头加上typedef关键字,myint_t就是我们定义的新类型
示例2:
void (*pfunA)(int a); ———— 传统变量(函数)声明表达式
void (*PFUNA)(int a); ———— 使用新的类型名PFUNA替换变量名pfunA
typedef void (*PFUNA)(int a); ———— 在语句开头加上typedef关键字,PFUNA就是我们定义的新类型
可以参考这篇文章特别详细还有与#define的区别介绍
https://blog.csdn.net/liitdar/article/details/80069638
传结构体地址与传结构体指针二者都可以作为传出zhi参数,因为接受函数必须为其定义一个结构指针来接收,这样在函数内就可以修改结构体,在这点上二者没有区别。
定义结构体指针未分配地址空间就作为参数传递会,如果想把它作为传出参数的话,
要按照下面的格式来写
void get(struct student **p); //用p来接收
main()
{
struct student *a;
get(&a);
}
需要在get()函数中用malloc()为其 动态分配内存空间。
接收函数的结构体分配:在接收函数中理论上他会在它自己的函数栈帧复制一份实参结构体拷贝,如果你传的是结构体本身,这样你对结构体的修改不会对实参有影响。
使用< >进行头文件的引用的话,编译器会在安装路径中进行寻找;
使用“ ”进行头文件的引用的话,会在源目录中寻找;
两者分别用于那些自带头文件引用和自己编写的头文件引用,虽然在使用过程中,好像两者都是可以串着使用,但是建议写标准程序。
作用是: 作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值.
简单地说就是防止编译器对代码进行优化。
找到的原因如下:
相当于变量a好几个可能出现的数值,放入enum中表示同一个类型的值。
在C 语言中,枚举类型是被当做 int 或者 unsigned int 类型来处理的。
这个没有找到相关的内容,暂时是通过从给的资料中看到这些东西,并不能很好的理解这个关键字
总共有四种 auto、 register、 static、 extern
存储类是所有局部变量默认的存储类,auto 只能用在函数内,即 auto 只能修饰局部变量;
存储类用于定义存储在寄存器中而不是 RAM 中的局部变量。
静态的特征便是前面加的有 “ static ”;
static修饰局部变量时,修改了局部变量的存储位置,从原来的占中存储改为静态存储区。但是静态变量离开作用域后并没有被销毁,仍然驻留在内存中,知道程序结束,但是不能对其访问;
Static修饰全局变量时,它改变了全局变量的作用域,只在其声明的文件中可见,存储位置内有改变,仍在静态存储区中
函数的定义和声明默认情况下是extern的,但静态函数只是在声明他的文件当中可见,不能被其他文件所用,
全局变量(外部变量)是在函数的外部定义的,它的作用域为从变量的定义处开始,到本程序文件的末尾。在此作用域内,全局变量可以为本文件中各个函数所引用。编译时将全局变量分配在静态存储区。
有时需要用extern来声明全局变量,以扩展全局变量的作用域。