嵌入式C语言复习——Day2

32个关键字

杂项:sizeof、return

	#include<stdio.h>
	
	int main()
	{
	    int a;
	    printf("the a is %d\n", sizeof(a));
	    return 0;//输出为4
	}

sizeof:编译器给我们查看内存空间容量的一个工具
return:返回值

数据类型:int, char, long, short, unsigned, signed, float, double, void

c语言操作对象:内存
c语言通过数据类型关键字描述内存大小
short、int、long、char、float、double 这六个关键字代表C 语言里的六种基本数据类型。
在不同的系统或编译器上,这些类型占据的字节长度是不同的:
8bit = 1B
在32 位的系统上:
short 占据的内存大小是2 个byte;
int占据的内存大小是4个byte;
long占据的内存大小是4个byte;
float占据的内存大小是4个byte;
double占据的内存大小是8个byte;
char占据的内存大小是1个byte;//硬件处理的最小单位8bit ,1个字节
具体可以用sizeof测试
在这里插入图片描述
int根据具体硬件决定
编译器最优的处理大小:系统一个周期,所能接受最大处理单位
32位系统 32bit 4B int
16位系统 16bit 2B int
2B数的表示范围为65536
进制表示
十进制、八进制、十六进制、二进制
3bit——8进制 111——0x7 1000——0x8
int a = 010 //a为8
4bit——16进制 int a = 0x10//a为16

unsigned无符号:多表示数据
signed有符号:多表示数字
char a = -1; //0xff 补码
a>>1//a右移 符号位仍然存在
unsigned char b = -1
b>>1//b右移,可以变成0x00

浮点运算float、double
float 4B double 8B
浮点型常量
1.0 1.1 double
1.0f float

格式化输出语句格式化输出语句
void 语义符

自定义数据类型:struct、union、enum、typedef
自定义 = 基本元素集合

结构体struct 元素之间的和

	struct myabc{
		unsigned int a;
		unsigned int b;
		unsigned int c;
		unsigned int d;
	}; //告诉编译器自己定义一个内存组织,四个unsigned int的集合
	struct myabc mybuf;//对结构体变量化,实例一个变量
结构体顺序有要求;

共用体 union 共用起始地址的一段内容,技巧型代码

	union myabc{
		char a;
		int b;
	}; //共用体声明
	union myabc abc;//使用

enum 枚举 被命名的整形常数的集合
定义常数例如:

	#define mon 0
	#define tue 1
	#define wed 2
	enum abc{mon, tue, wed};//效果同上,不定义的话默认为0,1,2	
enum 枚举名称{常量列表};
例如
	enum abc{MOD = 100, TUE, WED};
	int main()
	{
		enum abc a1;
		printf("the a1 is %lu\n",sizeof(a1));
		printf("the %d\n",WED);
		return 0;
	}

typedef 数据类型的别名
可以自己定义数据类型的名字,提高代码可读性
例如:int a = 100; //a是一个int类型的变量
typedef int a; //a是一个int类型的外号
typedef usigned int u16;
通常定义为xxx_t;

逻辑结构关键字:

两大结构:分支和循环
if、else 条件

	if(条件表达式)
		xxx;
	else
		xxx;

switch、case、default 多分支

	switch(整型数字)
	switch(a)
	{
		case 1:
			break;
		case 2:
			break;
	}

do、while、for 循环
for:次数

		for(表达式1;表达式2;表达式3)
		{
			执行代码块
		}

执行表达式1,对循环变量做初始化;
判断表达式2,若其值为真(非0),则执行for循环体中执行代码块,然后向下执行;若其值为假(0),则结束循环;执行表达式3,(i++)等对于循环变量进行操作的语句;执行for循环中执行代码块后执行第二步;第一步初始化只会执行一次。
循环结束,程序继续向下执行。

while:条件,当值为真(非0)时, 执行循环体代码块。

		while(表达式)
		{
			执行代码块
		}

do:先执行再判断条件,它先执行循环中的执行代码块,然后再判断while中表达式是否为真,如果为真则继续循环;如果为假,则终止循环。因此,do-while循环至少要执行一次循环语句。

		do{
			执行代码块
		}while(表达式); 

continue、break、goto
goto只能在同一函数下跳转

对于资源属性中位置的限定关键词auto、register、static、const、extern、volatile

C语言根据变量的生存周期来划分,可以分为静态存储方式和动态存储方式。
静态存储方式:是指在程序运行期间分配固定的存储空间的方式。静态存储区中存放了在整个程序执行过程中都存在的变量,如全局变量。
动态存储方式:是指在程序运行期间根据需要进行动态的分配存储空间的方式。动态存储区中存放的变量是根据程序运行的需要而建立和释放的,通常包括:函数形式参数;自动变量;函数调用时的现场保护和返回地址等。

auto 默认情况,可省略,属于动态存储方式,可读可写
register 定义一些快速访问的变量,编译器会尽量安排CPU的寄存器去存放变量,若寄存器不足,变量还是放在存储器中
register int a;// 限制变量定义在寄存器上的修饰符
&取地址这个符号对register不起作用

int main()
	{
		register int a;
		a = 0x10;
		printf("the a is %d\n",a);
		return 0;
	}

static 静态
应用场景:修饰3种数据
1)函数内部变量
普通局部变量的值在初始时是不确定的,除非对其显式赋值。普通局部变量存储于进程栈空间,使用完毕会立即释放。
静态局部变量使用static修饰符定义,即使在声明时未赋初值,编译器也会把它初始化为0。且静态局部变量存储于进程的全局数据区,即使函数返回,它的值也会保持不变。变量在全局数据区分配内存空间;编译器自动对其初始化
其作用域为局部作用域,当定义它的函数结束时,其作用域随之结束

	#include <stdio.h>
	
	void fn(void)
	{
	    int n = 10;
	
	    printf("n=%d\n", n);
	    n++;
	    printf("n++=%d\n", n);
	}
	
	void fn_static(void)
	{
	    static int n = 10;
	
	    printf("static n=%d\n", n);
	    n++;
	    printf("n++=%d\n", n);
	}
	
	int main(void)
	{
	    fn();
	    printf("--------------------\n");
	    fn_static();
	    printf("--------------------\n");
	    fn();
	    printf("--------------------\n");
	    fn_static();
	
	    return 0;
	}

static定义的变量在全局数据区分配内存空间,只有定义它的函数结束作用域才结束,不会自己释放,普通变量位于栈区,由系统自动分配内存,使用完毕立即释放

2)函数外部的变量
全局变量定义在函数体外部,在全局数据区分配存储空间,且编译器会自动对其初始化。
普通全局变量对整个工程可见,其他文件可以使用extern外部声明后直接使用。也就是说其他文件不能再定义一个与其相同名字的变量了(否则编译器会认为它们是同一个变量)。
静态全局变量仅对当前文件可见,其他文件不可访问,其他文件可以定义与其同名的变量,两者互不影响。
file1.h如下:

	#include <stdio.h>
	void printStr();

在file1.c中定义一个静态全局变量hello, 供file1.c中的函数printStr访问

	#include "file1.h"
	 
	static char* hello = "hello cobing!";
	 
	void printStr()
	{
		printf("%s\n", hello);
	}

file2.c是我们的主程序所在文件,file2.c中如果引用hello会编译出错

	#include "file1.h"
	 
	int main()
	{
		printStr();
		return 0;
	}

上面的例子中,file1.c中的hello就是一个静态全局变量,它可以被同一文件中的printStr调用,但是不能被不同源文件中的file2.c调用。只在定义它的源文件内有效,其他源文件无法访问它

3)函数的修饰符
函数的使用方式与全局变量类似,在函数的返回类型前加上static,就是静态函数。其特性如下:
静态函数只能在声明它的文件中可见,其他文件不能引用该函数,不同的文件可以使用相同名字的静态函数,互不影响

	/* file1.c */
	#include <stdio.h>
	
	static void fun(void)
	{
	    printf("hello from fun.\n");
	}
	
	int main(void)
	{
	    fun();
	    fun1(); //无法访问fun1
	
	    return 0;
	}
	
	/* file2.c */
	#include <stdio.h>
	
	static void fun1(void)
	{
	    printf("hello from static fun1.\n");
	}

static函数可以很好地解决不同原文件中函数同名的问题,因为一个源文件对于其他源文件中的static函数是不可见的。

extern:在一个文件中引用另一个文件中定义的变量或者函数
1)引用同一个文件中的变量

	#include<stdio.h>
	
	int func();
	
	int main()
	{
	    func(); //变量num在func函数中是可以正常使用,因为func对num的调用是发生在num的声明和初始化之后
	    extern int num;// 需要使用extern告诉编译器变量存在
	    printf("%d",num); //2
	    return 0;
	}
	
	int num = 3;
	
	int func()
	{
	    printf("%d\n",num);
	}

2)引用另一个文件中的变量
extern这个关键字的真正的作用是引用不在同一个文件中的变量或者函数
main.c

	#include<stdio.h>
	int main()
	{
	    extern int num;
	    printf("%d",num);
	    return 0;
	}

b.c

	#include<stdio.h>
	int num = 5;
	void func()
	{
	    printf("fun in a.c");
	}

b.c中定义了一个变量num,如果main.c中想要引用这个变量,那么可以使用extern这个关键字,注意这里能成功引用的原因是,num这个关键字在b.c中是一个全局变量,也就是说只有当一个变量是一个全局变量时,extern变量才会起作用

3)引用另一个文件中的函数
extern除了引用另一个文件中的变量外,还可以引用另一个文件中的函数,引用方法和引用变量相似

const:只读的变量
1)修饰局部变量

	const int n=5;
	int const n=5;

都表示变量n的值不能被改变,需要注意的是,用const修饰变量时,一定要给变量初始化,否则之后就不能再进行赋值了。
2)常量指针与指针常量
常量指针是指针指向的内容是常量,可以有一下两种定义方式

	const int * n;
	int const * n;
需要注意的是一下两点:

1、常量指针说的是不能通过这个指针改变变量的值,但是还是可以通过其他的引用来改变变量的值的。

	int a = 5;
	const int *n = &a;
	a=6;

2、常量指针指向的值不能改变,但是这并不是意味着指针本身不能改变,常量指针可以指向其他的地址。

	int a=5;
	int b=6;
	const int* n=&a;
	n=&b;

指针常量是指指针本身是个常量,不能在指向其他的地址

int *const n;

需要注意的是,指针常量指向的地址不能改变,但是地址中保存的数值是可以改变的,可以通过其他指向改地址的指针来修改。

	int a=5;
	int *p = &a;
	int* const n = &a;
	*p=8;

3)修饰函数的参数
1、防止修改指针指向的内容
2、防止修改指针指向的地址

volatile:告知编译器编译方法的关键字,不优化编译
volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改。volatile 提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。如果没有 volatile 关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。所以遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。
一般说来,volatile用在如下的几个地方:

  • 中断服务程序中修改的供其它程序检测的变量需要加volatile;
  • 多任务环境下各任务间共享的标志应该加volatile;
  • 存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义;
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值