嵌入式小白学习笔记20180910

20180905

 

Unsigned char 是一个字节

C语言隐式转换:

(摘自CSDN):C语言规定,不同类型的数据需要转换成同一类型后才可进行计算。

相同类型之间:

1.字符必须先转换为整数

2.short型转换成int型

3.float转换成double,以提高运算精度

4.赋值时,一律右部值转换成左部类型

 

不同类型之间:

1.当整型数据和双精度数据进行运算时,则先将整型数据转换成双精度类型,再进行运算,结果为双精度型数据。

2.当字符型数据和实型数据进行运算时,则先将字符型数据转换成实型数据,再进行运算,结果为实型数据。

 

C语言规定的转换规则是由低级向高级转换

char,short —> int —> unsigned —>long —>double <—float

低级 ——————————————————->高级

 

 

Unsigned char t = 0x01;

Unsigned long int u = 0;

U = t;//u = 0x00000001;

结构小的转化成大的,系统自动转换,编译器会将结构大的区域多出的部分进行填充。若改为t = u;编译器会报worning,因为是大的转为小的,此时便需要使用强制类型转换。int型数值赋给char型变量时,只保留其最低8位,高位部分舍弃。如u=0x12345678,强转后变为0x78。

 

指针大小永远和CPU字长保持一致,不管是什么类型的指针(char、int等类型)。

 

万能指针 void *

void *和unsigned char *都是万能指针。因为大小相同,一切皆大小。Void *是约定的万能指针

如果形参为void *x,则*x不能在函数中直接引用。因为不知道指向的是大小多少的空间,需要强转成其他类型。若写成unsigned char *x,则可以直接引用*x,长度为1字节。

(摘自CSDN):void *是一种指针类型,常用在函数参数、函数返回值中需要兼容不同指针类型的地方。我们可以将别的类型的指针无需强制类型转换的赋值给void *类型。也可以将void *强制类型转换成任何别的指针类型,至于强转的类型是否合理,就需要程序员自己控制了。

 

C语言隐式转换:https://blog.csdn.net/qq_29169813/article/details/51181628

 

 

 

 

20180907

数组名称是指针常量。(不是常量指针,二者注意区分)

 

两个const连用(自己了解,面试题类型):

Const stu_t ay[2];

Const struct stu *const (*xp) = NULL;

 

关键字:typeof

 

Unsigned long int f[4];

f[1]===f[1*sizeof(unsigned long int)]

(数组计算方法)

 

函数指针:指向的是指令区域。

 

Int func(int a)

{

Int x=a;

Return (x);

}

Int func2(int a)

{

Int x=a;

Return (x);

}

 

Int main(int argc,const char *Argv[]){

Int ( *fp ) ( int ) = func;//函数指针,指向函数。

Func2(1);

Fp = func;

Fp(1);//这里fp即为func,若没有上一行fp=func2,则fp为func2;

Return 0;

}

 

函数指针与其指向的函数簇(只要符合那个函数的形式,函数指针均可指向)。例如上方代码的func和func2,就是函数簇。函数形式相同,入参个数和类型相同,即可看为相同类型的函数,函数簇。

 

int*  f(int a, int b);  //  指针函数,重点强调返回值类型是一个地址变量

int (*f)(int a, int b);   // 函数指针,强调一种函数类型

 

 

 

 

20180908

指针函数

指针函数,简单的来说,就是一个返回指针的函数,其本质是一个函数,而该函数的返回值是一个指针。

声明格式为:类型标识符 *函数名(参数表)

 

函数指针

函数指针,其本质是一个指针变量,该指针指向这个函数。总结来说,函数指针就是指向函数的指针。

声明格式:类型说明符 (*函数名) (参数)

 

区别:

指针函数本质是一个函数,其返回值为指针。

函数指针本质是一个指针,其指向一个函数。

写法:

指针函数:int* fun(int x,int y);

函数指针:int (*fun)(int x,int y);

可以简单粗暴的理解为,指针函数的*是属于数据类型的,而函数指针的星号是属于函数名的。

再简单一点,可以这样辨别两者:函数名带括号的就是函数指针,否则就是指针函数。

 

malloc的全称是memory allocation,中文叫动态内存分配,用于申请一块连续的指定大小的内存块区域以void*类型返回分配的内存区域地址,当无法知道内存具体位置的时候,想要绑定真正的内存空间,就需要用到动态的分配内存。

malloc用法:

指针名=(数据类型)malloc(长度),(数据类型)表示指针.

举例1:int* buffer = (int*)malloc(8 * sizeof(int));

 

 

 

 

20180909

单向链表:链式的存储结构,在逻辑上是连续的,每次通过一个指针来指向下一个节点将其链接起来。

 

单向循环链表:与单向链表的区别就是,单向链表的最后一个节点指针是指向NULL的,单向循环链表最后一个节点的指针是指向头节点head的。

 

双向链表:包含两个指针,一个(prior)指向前一个节点,一个(next)指向后一个节点。 

 

 

双向循环链表:最后一个节点的next指向head,而headprior指向最后一个节点,构成一个环。

 

 

 

 

20180910

 

 

声明和定义:

Int func(int a){

}

Int main(){

Int func(int);//声明,声明入参类型,告诉编译器,这个符号存在过

Func(0x02);//调用

}

 

extern 关键字:如果声明里没有extern,表示当前符号一定在当前本模块(一个.c文件)内出现

如果加了extern,表示这个符号原则上应该在其他文件的其他模块中出现过,是共享的。链接器会找到,若找不到,则报错。

关于extern关键字:

1.声明可以多次,定义只能一次。

2.关键字extern用于扩展变量和函数的可见性。

3.由于函数默认存在extern,不需要再定义和声明的时候使用extern

4.当变量使用extern时,它只是声明没有定义。

5.当变量用extern声明并且有初始化时,和变量的定义一样。

 

 

Int main(){

Extern int func(int);//声明,声明入参类型

Func(0x02);//调用

}

 

不管什么类型的指针,指针都占4个字节。

 

Char *p=((void *) 0);//相当于char *p=NULL;赋初值,但是不是实例化。实例化:给指针指向一段有意义的空间。

 

P=(char *)malloc(sizeof(char));//运行到这里,向一段预定的区域,动态分配一块可用的内存。若到这里内存不够,则返回为空。

 

Heap:堆空间(专门用于动态内存分配,必须自己操作,编译器不会管)(可以认为是一段“永久空间”,生命周期随着main函数的结束而结束)

Stack:栈空间(由编译器自己操作)(可以认为是临时空间)

堆内存大,栈内存小。

对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memory leak

对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列。

堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。

栈的效率比堆的效率高。

 

 

Malloc分配的空间,如果不手动释放,则一直占用空间。空间分配在堆里。

静态分配的内存是有作用域的。

Malloc是空类型,需要进行强制类型转换。

 

Int main()

{

#define NULL((void *(0)

Char a = 0x01;//静态分配的内存,空间在栈里。当函数结束,这段空间将被抹掉,将来可能会在其他函数中被复用。若程序结束后还想使用,可用static。但是static为不可重入函数,在多线程中则无法使用。

Char *p=NULL;

P=&a;

P=(char *)malloc(sizeof(char));

 

Func(0x02);

Retuen 0;

}

 

C语言中static的三种用法(摘自CSDN):

1.全局变量:

在全局变量之前加上关键字static,全局变量就被定义成为一个全局静态变量。

1)内存中的位置:静态存储区(静态存储区在整个程序运行期间都存在)

2)初始化:未经初始化的全局静态变量会被程序自动初始化为0(自动对象的值是任意的,除非他被显示初始化)

3)作用域:全局静态变量在声明他的文件之外是不可见的。准确地讲从定义之处开始到文件结尾。

好处:

定义全局静态变量的好处:

<1>不会被其他文件所访问,修改

<2>其他文件中可以使用相同名字的变量,不会发生冲突。

2.局部静态变量

在局部变量之前加上关键字static,局部变量就被定义成为一个局部静态变量。

1)内存中的位置:静态存储区

2)初始化:未经初始化的全局静态变量会被程序自动初始化为0(自动对象的值是任意的,除非他被显示初始化)

3)作用域:作用域仍为局部作用域,当定义它的函数或者语句块结束的时候,作用域随之结束。

3. 静态函数

在函数的返回类型前加上关键字static,函数就被定义成为静态函数。

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

定义静态函数的好处:

<1> 其他文件中可以定义相同名字的函数,不会发生冲突

<2> 静态函数不能被其他文件所用。 存储说明符autoregisterexternstatic,对应两种存储期:自动存储期和静态存储期。 autoregister对应自动存储期。具有自动存储期的变量在进入声明该变量的程序块时被建立,它在该程序块活动时存在,退出该程序块时撤销。

关键字externstatic用来说明具有静态存储期的变量和函数。用static声明的局部变量具有静态存储持续期(static storage duration),或静态范围(static extent)。虽然他的值在函数调用之间保持有效,但是其名字的可视性仍限制在其局部域内。静态局部对象在程序执行到该对象的声明处时被首次初始化。

由于static变量的以上特性,可实现一些特定功能。

 

可重入函数和线程安全函数(摘自CSDN):

可重入函数是由于一个任务并发使用,而不用担心数据的错误,相反,不可重入函数不能被一个任务所共享,除非能确保函数的互斥(使用信号量或禁用中断)。可重入函数可以在任意时刻被中断,稍后再运行,数据不会产生问题。不可重入函数要么使用局部变量,要么使用全局变量时保护自己的数据(加锁等方式)。

使用了静态变量(全局&局部)或是静态函数的,为不可重入函数。

 

 

 

线程安全函数和可重入函数的关系:

1)可重入函数一定是线程安全函数

 

2)线程安全函数不一定是可重入函数(有可能通过互斥机制实现线程安全不安全函数—>线程安全函数的转换等)

 

3)可重入性要强于线程安全性(相当于函数产生相同结果时可重入性的条件要苛刻)

 

 

 

 

C程序一直由下列部分组成(摘自CSDN):

1)正文段——CPU执行的机器指令部分;一个程序只有一个副本;只读,防止程序由于意外事故而修改自身指令;   

2)初始化数据段(数据段)——在程序中所有赋了初值的全局变量,存放在这里。   

3)非初始化数据段(bss段)——在程序中没有初始化的全局变量;内核将此段初始化为0    

4)栈——增长方向:自顶向下增长;自动变量以及每次函数调用时所需要保存的信息(返回地址;环境信息)。     

5)堆——动态存储分。是向高地址扩展的数据类型,是自下向上的扩展方式

 

 

变量的定义和声明:

定义只能一次,声明可以多次。

定义也是声明(定义变量时声明了类型和名字)。

定义会分配存储空间,声明不会。

 

 

如果声明有初始化式,就被当作定义,即使前面加了extern

 

 

可重入函数和线程安全函数:https://blog.csdn.net/skyroben/article/details/72900748

变量的声明和定义:https://blog.csdn.net/gatieme/article/details/50640424

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值