.bss: uninitialized or zero-initialized global and static variables
.data: initialized global and static variables
.text: Read only, code and const
pre-compiler: #define, #include 【text substitution】
compiler: turn source code into machine code(object file), perform syntax error check
link: link these object files together to create an executable file, resolves references to functions or variables that are defined in other object files【map file里面可以看到】
Macro写一个函数: Macro本质就是pre-processor将内容进行文本替换
#define SET_BIT(var, position) var = var | (1<B)?A:B
typedef 和 macro哪个好
const的含义: Read only
volatile的含义: tell compiler not to use cache to optimize, always to read from address.
const 和 volatile公用:
uint8_t const volatile * reg_1 = (uint8_t *) 0x10000000;
对固定地址赋值
*(unsigned int *)0xFC880000 = 1;
extern: change visible scope
static 修饰
sizeof (sizeof也是个keyword): 返回的是byte数
sizeof(int)
sizeof(Node) //typedef struct{} Node;
&
|
^ (exclusive or)
~: unsigned int mask = ~(0);
字符和字符串
end with \0; NULL character
qsort 对数组排序
#include
int compare( const void *a, const void *b)
{
return *(const int*)a - *(const int*)b;
}
int main()
{
int m[] = {1,3,5,2,6};
int num = sizeof(m)/sizeof(m[0]);
int size = sizeof(m[0]);
qsort( m, num, size, compare);
printf("0x%x\n", m[0] );
printf("0x%x\n", m[1] );
printf("0x%x\n", m[2] );
printf("0x%x\n", m[3] );
printf("0x%x\n", m[4] );
return 0;
}
注:
1. compare的返回值永远是int, 但是 如果输入数组是char,那么return那行
就要写成 *(const char*)a 【否则不工作】
2. return 那行的 *(const char*)a,星号不要忘了
3. 三个int 变量,啪啪啪写完朝函数里面放就行了
4. qsort是void类型,没有返回值
malloc 分配空间
void *malloc(size_t size) //返回的是void型指针
char *p;
p = (char*) malloc( sizeof(char) * 15 ); //15个元素的空间
data alignment: data will be padding
虽然sBa[20],但是仍然看做是2byte的长度,所以结构体还是以 4bytes的长度 来 alignment的
typedef struct
{
int Num;
short sDate;
char cha[2];
short sBa[20];
}Test;
void: 可以指向任何类型, qsort的函数就有用到。使用的时候要记得 强制类型转换
wild: not been initialized to anything
NULL: a pointer which is pointing to nothing
dangling: A pointer pointing to a memory location that has been deleted (or freed)
没有权限访问该地址,所以*p 直接就报错了
空指针,不指向任何地址。在新建链表的时候会用到
直接对物理地址赋值:
* (int*) 0xFF00CCFF = 1;
或者: 【 地址前的 (int*)不要忘了 】
int *p = (int*) 0xFF8800FF;
*p = 1
从上图代码可以看出:
二维数组parr[0][0],可以拆开看成 ( parr[0] )[0], 也就是(arrl)[0];
使用很广,中断向量表里面存的就是函数指针
用的时候:
void(*p)(void);
或者
void(*0xF32D0000)(1,2);
typecasting:
int will be promoted to unsigned int
一个数组,再加一个栈顶指针
strlen(const char* str);
void* malloc(size_t size);
void free(void *ptr);
void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*));
auto: default storage class, for local variable 【storage duration is automatic,be created when the program execution enters the block in which it is defined and destroyed when the block exits】
register: only for local variables, store in cpu register instead of RAM 【& cannot be used on register variable】
enum:
bit field:
说白了就是 int A 后面带一个 :n 即可
// 定义
typedef struct
{
int a;
}A;
typedef struct
{
int a_bit0 :1 ;
int a_bit1 :1 ;
int a_bit2 :1 ;
int a_bit3 :1 ;
int a_reserved :28 ;
}A_bitfield;
//使用
A m;
m.a;
A_bitfield n;
n.a_bit0;
switch case:
Exp1 ? Exp2 : Exp3;
i++ / ++i
0xFF
0b011
%s
%d
%f
char 1bit
short 2bit
int: 4 bytes
short vs long:8 bytes
double:
float:
runtime error: X is local variable
前提: 有两个共享的resource A和 B,task 1和2 都需要 A和B 两个资源
task1使用了resource A,然后被task2抢占,task使用了resource B,然后发现resource A不可用,于是进入wait 模式【此时B没有被释放】。 task1拿回cpu控制权继续执行,然后发现 resource B不可用,互相wait
解决: timeout,如果等待时间timeout以后,task需要释放自己的resource
Priority Inversion
前提:有一个共享的resource 【优先级3>2>1】
优先级1的task 被 优先级3的task抢占,但task3在执行过程中发现share resource不可用【被task1用着呢】,于是释放了cpu【进入wait,任务就绪表置0,触发scheduler】,scheduler根据任务就绪表让task1继续执行,但此时task2又抢占了task1并执行完成,
解决:临时提升低优先级任务的优先级。 task3在因为resource释放cpu的时候,把持有resource的task1优先级临时提升到3,这样task2 就不能抢占他了
【因为basic task中没法处理share resource,所以只有extended task需要考虑deadlock 和优先级反转】
多核间通讯: IOC, spinlock
就一个core,task发现resource 不能用的时候,就只应该立刻释放cpu 【mutex + semaphore】
多核的时候,才有一个core 来while(1),等待另一个core的task运行完release resource的道理【spinlock】
因为spinlock用于多核cpu,其中一个core一直while(1)等待另一个core释放资源,也无所谓 【Spin locks are a low-level synchronization mechanism suitable primarily for use on shared memory multiprocessors. When the calling thread requests a spin lock that is already held by another thread, the calling thread spins in a loop to test if the lock has become available】
mutex VS semaphore
都是用来做进程间同步的,区别是mutex必须是进程自己释放,semaphore可以是别的进程释放,而且可以大于1
semaphore: 【由计数器和 任务等待表 两部分组成,也就是说每个信号量都有自己的任务等待表】
所以scheduler的工作很简单,在任务就绪表里面找最高优先级的任务【有更高的就上下文切换】
说白了extended task,就是task可以【因为共享资源不可用】主动放弃cpu控制权,进入wait状态,让优先级低的先去执行【任务就绪表置0,任务等待表置1】
basic task,task没法自己主动放弃cpu,只能是被动的被其他优先级更高的抢占
scheduler被调用的场景:
任务就绪表【1张】 + 任务等待表【多张,每个信号量都有自己的1张任务等待表,信号量在被task释放的时候,该task会去该信号量的任务等待表唤醒最高优先级的任务进入任务就绪表,然后触发一次scheduler】
scheduler做的事情:
查找任务就绪表优先级最高的任务,如果需要切换,就context switch切换。否则就继续执行当前任务,开销很小
针对超过一个byte的数据而言。most significant byte在低地址的为big endian
检测方法:
int a = 0x12345678;
char *p = (char*)&a; //(char*) 告诉编译器用char类型来解析a地址的数据
注:
通过char型指针p变量,获取第一个byte,既可判断
a suggestion to the compiler that it should generate code for the function at the call site, instead of generating a separate function call. for better performance
only a suggestion, compiler will make the final decision
<>: 寻找 system path(编译器的安装目录文件夹)
"": 寻找当前project path(当前工程文件夹),找不到再找system path
【以下针对嵌入式MCU而言】
单核:
【linker里面配置了stack的大小,startup phase把stack pointer指向了该位置, 之后main函数入的就是这个栈。只是说操作系统在任务切换的时候,会把cpu register内该task的信息copy到那个task自己的任务控制块里面零时存起来,保护现场。之后再copy回来,就等于恢复现场,可以继续运行了】
【对于操作系统,每个task都要有自己的任务栈,运行的时候,cpu的stack pointer要指过去,是为了方便任务切换。如果所有task公用一个栈,假如task1先入栈运行,然后被优先级更高的task2抢占,入栈到它上面,然后task2运行一半休眠了,那么就没法access到task1的栈内容了。就算你把task2的栈pop出来去存储,也太麻烦了,消耗时间太多】
多核:
中断向量表网站链接:(array of function pointers)
interrupt: trigger by external event, save context and jump to the ISR
下图可以看到,Interrupts and exceptions 都在 中断向量表里面
Preemptive OSes are often used in real-time systems where tasks must meet strict deadlines. The OS can guarantee that high-priority tasks will run when required.
some preemptive OSes use time slicing, where each task is given a fixed time quantum to run. When the time quantum expires, the task is preempted even if it hasn't finished.
函数入栈流程网站链接:
函数栈从高地址到低地址增长
return address, actual parameters and local variable are pushed into stack【返回地址就是下一行该执行的代码的地址】
ebp, esp stands for base pointer and stack pointer
一道很好的题目
save the current status of task into control blocks 【register, task stacks】
trigger by interrupt, pre-emptive multi-task,
memory mapping 的时候,用到过
正数的原码,反码,补码都一样
负数的原码:和正数一样,除了符号位置1 【问题,正负数原码相加不为0】
反码(ones' complement):直接把正数的原码反过来【问题,正负数反码相加为0xFFFF】
补码(twos' complement):反码+1 【正负数补码相加不为0】
的正确用法:
int a[10] = {0}; //记得将所有元素初始化为0 【有些在线编译器很傻逼】
num = num <<4; // 记得写num =, 单独的num<<4 不会改变num本身的值
unsigned int mask = ~0; //如果要位运算,一定记得是unsigned,要么就直接 (~0)<<8
常用:
int a[] = “abcdefg”;
sizeof(a);
printf(“%s\n”,a);
基本上:
数组题,就可以考虑先qsort一下,可能会简单很多
数操作,就是从2进制的角度去看, XOR, 一下什么的。 &1111 就是截取, |0000就是删除
不知道循环次数的时候, while(n) 就很好用
数字题的工具:
截取: &1111
删除: |0000
半加法: XOR
取某一个bit: n&1 n = n>>1
char型指针可以很方便的操作int型变量的每一个byte
二进制字符串转数字: 找到1的位置, n = n| (1<
找到的元素,可以用一个数组把下标都存起来,然后再操作
不知道循环长度,可以 while() 循环
将某一段bit翻转: ^1111
找不同: XOR 的结果为1
第5条: 0x5A5A,5A5A 想变成 0xA5A5,A5A5
第8条:
数组题的工具:
qsort
删除重复的数: XOR
有的时候,搞个int型指针,就可以一次操作4个char数组元素
qsort
malloc
free
XOR实现加法
#include
int add( int a, int b)
{
int sum = a^b;
int new = a&b;
if( new==0 )
{
return sum;
}
else
{
return add(sum, new<<1);
}
}
int main()
{
printf("%d\n", add(3,21));
return 0;
}