C语言的进阶学习笔记

STM32编程中C语言学习

项目需要学习STM32中的一些函数的使用,但其中涉及到许多指针、结构、变量等等,虽然在学校的C语言基础课程中已经学习了一部分,但这一部分过于基础,所以针对性的又学习了算是进阶的知识点,这里主要参考这篇文章,以及学长发的文件中的学习笔记进行针对性的学习

https://www.cnblogs.com/lnleelove/p/9751804.html

逻辑运算以及位运算

与、或、非运算

  1. “|”: 或的符号,1|1=1、1|0=1、0|0=0,只要有1则为1;
  2. “&”: 与的符号,1|1=1、1|0=0、0|0=0,只要有0则为0;
  3. “~”: 非的符号, ~1=0、 ~0=1,等于取反;
  4. “^”: 异或的符号,两个位相同为0,相异为1;
    ** 位运算**
  5. “>>” 位左移,各二进位全部右移若干位,对无符号数,高位补0,有符号数,各编译器处理方法不一样,有的补符号位(算术右移),有的补0(逻辑右移);
  6. “<<” 位右移,各二进位全部左移若干位,高位丢弃,低位补0;

#ifdef 和 #ifndef

#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

概述

typedef为C语言的关键字,作用是为一种数据类型定义一个新名字,这里的数据类型包括内部数据类型(int,char等)和自定义的数据类型(struct等)。
typedef本身是一种存储类的关键字,与auto、extern、static、register等关键字不能出现在同一个表达式中。

typedef的用法

使用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()为其 动态分配内存空间。
接收函数的结构体分配:在接收函数中理论上他会在它自己的函数栈帧复制一份实参结构体拷贝,如果你传的是结构体本身,这样你对结构体的修改不会对实参有影响。

文件的包含问题–头文件的引用

使用< >进行头文件的引用的话,编译器会在安装路径中进行寻找;
使用“ ”进行头文件的引用的话,会在源目录中寻找;
两者分别用于那些自带头文件引用和自己编写的头文件引用,虽然在使用过程中,好像两者都是可以串着使用,但是建议写标准程序。

Volatile 语句

作用是: 作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值.
简单地说就是防止编译器对代码进行优化。
找到的原因如下:

  1. 因为从寄存器取值比从内存取值快很多。
  2. 所以编译器它就觉得能优化,就把一个变量放在寄存器中。以后取这个变量就在寄存器取就行了。内存里那个数怎么变就无所谓了。
  3. 所以volatile的作用就是告诉编译器,别优化我这个变量。

Enue关键字

相当于变量a好几个可能出现的数值,放入enum中表示同一个类型的值。
在C 语言中,枚举类型是被当做 int 或者 unsigned int 类型来处理的。
这个没有找到相关的内容,暂时是通过从给的资料中看到这些东西,并不能很好的理解这个关键字

C储存类型

总共有四种 autoregisterstaticextern

auto

存储类是所有局部变量默认的存储类,auto 只能用在函数内,即 auto 只能修饰局部变量;

register

存储类用于定义存储在寄存器中而不是 RAM 中的局部变量。

static

静态的特征便是前面加的有 “ static ”;

全局变量静态(static)

  1. 内存中的位置:静态存储区(静态存储区在整个程序运行期间存在);
  2. 初始化:未经初始化的静态全局变量会被程序自动初始化为0,普通全局变量未经初始化的值是任意的;
  3. 作用域:全局静态变量的只在声明它的文件下是可见的(从定义到文件结尾),普通全局变量在整个工程中是可见的。
优点:
  1. 不会被其他文件访问和修改;
  2. 其他文件使用相同的名字的变量不会发生冲突

局部静态变量

  1. 内存中的位置:静态存储区;
  2. 初始化:未经初始化的静态局部变量会被程序自动初始化为0,普通局部变量未经初始化的值是任意的;
  3. 作用域:作用域仍然是局部的,当定义它的函数或语句块结束时,作用域也随之结束。
注意:

static修饰局部变量时,修改了局部变量的存储位置,从原来的占中存储改为静态存储区。但是静态变量离开作用域后并没有被销毁,仍然驻留在内存中,知道程序结束,但是不能对其访问;
Static修饰全局变量时,它改变了全局变量的作用域,只在其声明的文件中可见,存储位置内有改变,仍在静态存储区中

静态函数

函数的定义和声明默认情况下是extern的,但静态函数只是在声明他的文件当中可见,不能被其他文件所用,

  1. 静态函数在其他文件中科技定义形同的名字,不会发生冲突;
  2. 静态函数不能被其他文件所用;
  3. 静态函数会被自动分配在一个一直使用的存储区,直到退出应用程序实例,避免了调用函数时压栈出栈,速度快很多。
一些找到的Q&A
  1. static全局变量与普通的全局变量有什么区别:static全局变量只初使化一次,防止在其他文件单元中被引用;
  2. static局部变量和普通局部变量有什么区别:static局部变量只被初始化一次,下一次依据上一次结果值;
  3. static函数与普通函数有什么区别:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝。

extern

全局变量(外部变量)是在函数的外部定义的,它的作用域为从变量的定义处开始,到本程序文件的末尾。在此作用域内,全局变量可以为本文件中各个函数所引用。编译时将全局变量分配在静态存储区。
有时需要用extern来声明全局变量,以扩展全局变量的作用域。

你可能感兴趣的:(物联网-动物的物联网,c++,c语言)