1 CPU对寄存器的读写一般是按照数据宽度一起进行的,也就是32bit读入,32bit写入,也就是假设我们只想修改其中某一个位的话,也是整体读取,修改特定位,然后整体写入
2 寄存器特定位清零用& var1 = 0xAAAAAAA若想将8到15位清零,可以使用 var1 &= 0xFFFF00FF
3 特定位置1用或 | var1 = 0xAAAA00AA置1 var1 |= 0x0000FF00
4 寄存器特定位取反 ^
5 使用宏定义来完成位运算 将该位和1进行或操作 #define SET_BIT_N(x,n) ((x)|((n)-1))
6 使用宏复位 将该位和0与,其它位和1与 #define CLEAR_BIT_N(x,n) ((x)&~((n)-1))
7 所谓的段错误就是地址错误,一般是指针指向的地址不存在或者写受到限制导致的
8 const一旦定义不能修改
9 数组传参,传的是数组元素的首地址
10 #define只是简单的宏替换,在预处理的时候进行处理 typedef是重定义 在编译时进行处理
11 strlen以\0作为标记区分,但统计不包括 \0
12 常量也称为字面量,没有对应的存储单元
13 typedef本身并不产生新的变量类型,而是给现有变量起一个别名,类型本身并不占用内存,而变量是这个磨具的实例
14 Linux命令行默认缓冲,直到遇到\n \r\n \r或者退出时才会输出,所以,调试时最好加上\n以免误判错误位置
15 scanf不会接收最后的\n 等下次scanf接收时,却会收到它,可能导致并没有拿到我们想要的数据,注意下这点
16 内存管理方式:栈(stack),堆(heap),数据区(.data和.bss区)和常量区(.ro.data)
17 栈内存管理的特点:
1)运行时自动分配,运行结束自动回收
2)可以反复使用
3)脏内存,它可以反复使用,每次使用后并不会去清空内存,下次该空间被再次分配时上次使用的值还在
4)临时性,函数不能反悔指针变量,因为程序运行结束之后该空间就会被释放
18 堆内存的特点:
1)空间较大
2)要手动申请和释放
3)脏内存,在使用完也不会清除数据
4)在malloc后和free前可以访问,malloc前和free后不可再访问,否则会造成不可预知的错误
注:若分配的内存未手动释放,这块空间会一直被占用,只有整个程序结束时才会被释放
malloc返回的是viod *型的指针,它表示万能指针,申请失败返回NULL
malloc的一些细节表现:
malloc(0)这么操作是没有意义的,假设真的这么操作,它的返回值是不确定的
malloc(4)GC中的malloc是以16B为单位进行空间分配的,若指定空间小于16B,会分配16B
19 (.text)代码段:存放代码,程序的各种函数指令就存放在这里
(.data)数据段:也称数据区 静态数据区 静态区,程序中的静态变量空间开辟于此
.bss段:又称ZI(Zero Initial)段,所有的未初始化的静态变量存放在这里,自动把他们初始化为0
.data .bss无本质差别,只是data用来存放显式初始化为非0的数据
bss用来存放显式初始化为0或者未初始化的数据
20 C中Const的试下有两种:
1 存放在代码段,(代码段只读),来达到不能修改,单片机常这么做
2 让编译器帮忙实现,编译器发现const修饰的变量试图被修改时会提示错误,本质是和普通变量一样的,GCC是这么做的
21 C中字符串的本质是指向字符存放地址的指针
对于char *p = "linux"来说 p是指针变量,占用4或者8个字节 Linux存储于代码段,占用6个字节
22 sizeof得到的是类型的占用字节大小,在编译阶段就可以确定大小
strlen得到的是字符串的长度
23 #prama pack(n) 告诉编译器,我们希望以几个字节对齐
24 结构体是多个独立元素(地址空间)打包在一起,union是一个元素(地址空间)的不同解析方式
union的sizeof检测到的值是各个元素占用空间最大的那个元素的大小,不存在内存对齐,因为只有一个元素
struct的sizeof检测到的是所有元素占用内存的总和,要考虑内存对齐
25 GCC中一些常见的文件扩展名
.c C语言源代码
.a 目标文件构成的静态库文件
.h 头文件
.i 经过预处理的C源码文件
.ii 预处理后的C++源文件
.m Object-C 源文件
.o 编译后的目标文件
.out 连接器生成的可执行文件
.s 汇编源文件,不再进行预处理,不可包含预处理指令
.S 汇编源文件,还会进行预处理,可以包含预处理指令
26 编译链接的四个步骤:
预处理 gcc -E *.c -o *.i
编译 gcc -S *.i -o *.s
汇编 gcc -c *.s -o *.o
链接 gcc *.o -o *.out
17 #include <> 会在系统目录中查找库文件
#include "" 会现在用户目录中查找
18 静态链接库就是将自己的库文件只编译不链接形成的.o目标文件,用ar工具归档成.a文件,使用时,会将库中的文件直接复制到使用它的文件中,若有多个文件include,就会复制多份到内存中,造成内存浪费
静态链接库不是将库文件直接复制到可执行程序,只是做一个链接标记,当程序需要时,加载到内存中,其它程序也需要时直接使用,在内存中只有一份
19 制作静态链接库
//demo.h
void func1(void);
int func2(int a,int b);
//demo.c
#include <stdio.h>
void func1(){
printf("func1 in demo.c\n");
}
int func2(int a,int b){
printf("func2 in demo.c\n");
return a + b;
}
//test.c
#include <stdio.h>
#include "demo.h"
int main(){
func1();
int a = func2(4,5);
printf("a = %d\n",a);
return 0;
}
制作静态库:
gcc demo.c -o demo -c
ar -rc libdemo.a demo
1)使用命令gcc test.c -o test 会报错
clang: error: linker command failed with exit code 1 (use -v to see invocation)
原因是没有找到库函数demo.a
2)使用命令 gcc test.c -o test -ldemo
ld: library not found for -ldemo
clang: error: linker command failed with exit code 1 (use -v to see invocation)
原因是默认库文件查找路径为用户动态库的文件夹
3)gcc test.c -o test -ldemo -L.
可以正确执行,-L指定动态库的查找路径 .表示当前路径
20 制作动态链接库
gcc -c demo.c -o demo -fPIC
gcc -o libdemo.so demo -shared
1)使用命令gcc test.c -o test 会报错,同上静态库的错误信息
2)使用命令 gcc test.c -o test -ldemo同上
3)gcc test.c -o test -ldemo -L. 可以
21 1)register关键字很少用,使用时,系统会尽量把它分配到寄存器,效率会很高
但它没有内存地址,不能使用&符号,而且不能保证每次都分配到寄存器,只能尽量
变量的长度应小于寄存器的长度
22 在C中若变量从定义到使用始终未赋值,则在编译和运行虽然可以通过,却会得到意想不到的结果