Bootstrap

嵌入式C语言增强

所有的变量都存在RAM中(包括指针变量)

const(常量)存在Flash中

指针都是存放的地址,所以指针的大小是根据设备的大小,例如32位操作系统,一个指针的大小是4B,64位就是8B。

int *p1;

char *p2;

sizeof(p1);

sizeof(p2);

在32位操作系统中大小都为4B。

sizeof(*p1);

sizeof(*p2);

*p1的大小为4B,因为p1指向int型数据

*p2的大小为1B

关于volatile(易变的,易怒的)

就是让编译器不要优化,因为有些变量会在放在cpu里面,编译器优化就不去读内存的东西,就导致变量改变了不知道,一定要用volatile的地方:读取寄存器。

const 常量

static 关键字不能和extern一起用,加了static就只能作用于这个.c文件

结构体

typedef struct Person

{

        char *name;

        int age;

        char *sex;

        struct Person *classmates;   指针占用大小就4个字节是确定了的,可以这么用。

        struct Person classmates      这样无法确定classmates的占用字节数会导致无限递归

}Person,*p;  这样表示可以用Person表示结构体,p表示结构体指针。

Person p1 = {'tsui',24,'male'};

Person p2 = {'chen',25,'female'};

p1.classmates = &p2;

p2.classmates = &p1;

可以打印 p1.classmates->sex   输出结果为female

函数指针。

void singsong(void)

{

        printf("sing");

}

typedef struct Person

{

        char *name;

        int age;

        char *sex;

        struct Person *classmates;   //指针占用大小就4个字节是确定了的,可以这么用。

        void (*Specialty)(void);        //函数指针占用四个字节

}Person,*p;  

Person p ={'tsui',24,'male',&singsong};//对于函数而言这个&加不加都可以。

使用p.Specialty

关于typedef  => type def 类型定义 

typedef int A;

typedef struct person{} person; 

与宏定义#define 的区别

不能使用typedef 1 A;

#define PI 3.14

进阶

typedef void (*method) (int,int); 定义了一个函数指针类型

method m1;

method m2;

插入链表

typedef struct Node

{

        char *name;

        struct spy *next;

}spy,*spy_node;



spy A = {'A',NULL};

spy B= {'B',NULL};

spy C= {'C',NULL};

spy D = {'D',NULL};



spy_node head =  NULL;

void insert(spynode node){

        spy_node last;

        if (head == NULL) {

                head = node;

                node->next = NULL;

        } else {

               last = head;

                while(last) {

                          if (last->next == NULL){

                                break;

                        }else {

                                last = last->next;

                        }              

                }

           last -> node = node;

           node -> next = NULL;                                  

         }

}

void remove(spynode node)

{

        spynode left;

        if(head == node) {

                head ->next = NULL;

        } else {

                left = head;

                while(left) {

                        if (left->next == node) {

                                break;

                        }else {

                                left = left->next;

                        }

                }

                if(left) {

                        left->next = node->next;

                }

        }

}

执行一段程序

int a = 1;

int b = 2;

a = a + b;

CPU一般只作为计算单元,内存是保存变量的地方。在CPU中会有寄存器,会保存内存中的值,这样可以快速进行计算后,再写入内存当中。因此上一段代码执行汇编会分三个步骤

1.读内存中的数据写入寄存器

2.CPU进行加法

3.把寄存器中的数据写回内存。

指令 【源】【目的】

load R0 a

load R1 b

ADD R0,R0,R1

STR R0 a

有值的全局变量初始化

类似memcpy,把flash上的数据段整体拷贝到RAM

初始化为0,没有初始化的全局变量,怎么初始化?

这些变量在内存都放在ZI段,类似于memset把ZI段全部清零。

做完上面一切才去调用main函数。

RO-data是 Read Only 只读常量的大小,如const型;

RW-data是(Read Write) 初始化了的可读写变量的大小;

ZI-data是(Zero Initialize) 没有初始化的可读写变量的大小。ZI-data不会被算做代码里因为不会被初始化;

简单的说就是在烧写的时候是FLASH中的被占用的空间为:Code + RO Data + RW Data

程序运行的时候,芯片内部RAM使用的空间为: RW Data + ZI Data

---------------------------------------------------------------------------------------------------------------------

16位系统指针大小为2个字节,64位为8个字节

int *p  表示指向int类型的指针p

指针的加加减减一般用于数组,为了避免指针越界。

数组名就是一个指针变量

普通的传递参数,是把一个这个参数在内存中复制一份,实际上传递的是复制的数据。这样做的原因类似于抄作业,抄作业不能更改源文件。但是一旦抄的作业过多那么就出现了问题,既浪费空间,又浪费时间。因此引出了指针传参,但是在子函数修改传入的数组,那么主函数的数组值也会改变,因此加入const只读。

指针加code是访问RAM

函数指针和指针函数(括号的优先级)

指针函数 返回指针的函数 主体是函数,返回值是一个指针

int* fun(int,int); 

int * fun(int,int);

int *fun(int,int);

以上三种声明都可以,第一种更加直观 返回值是 int* 类型

#include<stdio.h>

int* fun(int* x)    //传入指针 

{

       int* tmp = x;   //指针tmp指向x

    return tmp;       //返回tmp指向的地址

}

int main()

{

    int b = 2;     

    int* p = &b;   //p指向b的地址

    printf("%d",*fun(p));//输出p指向的地址的值

    return 0;

}

输出2

函数指针

函数指针是 指向函数的指针 主体是指针 指向的是一个函数的地址

注意 * 和函数名要用括号括起来,否则因为运算符的优先级原因就变成指针函数了

函数指针的参数列表要和函数指针指向的函数的参数列表一致

#include<stdio.h>

int add(int x,int y)

{

    return x + y;

}

int (*fun) (int,int);              //声明函数指针

int main()

{

    fun = &add;                              //fun函数指针指向add函数

    printf("%d ",fun(3,5));        

    printf("%d",(*fun)(4,2));

    return 0;

}

输出结果:8 6
上面的样例中,使用函数指针时使用fun(3,5)(*fun)(3,5)都可以

函数指针最大的用法回调函数

#include<stdio.h>

#define LEN 10

//定义函数指针函数 CallBack升级为函数指针类型

typedef void(*CallBack)(int *);

//函数原型声明

void showPstSeq(int *);

void showRevSeq(int *);

void showArray(int *,CallBack);



int main()

{

       int data[LEN] = {0,1,2,3,4,5,6,7,8,9};

       showArray(data,&showPstSeq);

       showArray(data,&showRevSeq);

}



void showPstSeq (int *data)

{

       printf("正序输出数组:");

       int i;

       for(i = 0;i < LEN;i++){

              printf("%d",data[i]);

       }

       printf("\r\n");

}



void showRevSeq(int *data)

{

       printf("逆序输出数组:");  

       int i;

       for(i=LEN-1;i >= 0;i--){

              printf("%d",data[i]);

       }

       printf("\r\n");

}

//注册函数,入参为函数指针(回调函数指针)

void showArray(int *data,CallBack callback)

{

       callback(data);    

}

结果:

;