系统程序员成长计划
—————————Chapter1 背景知识—————–
1.1函数命名
·文件名 :单词小写,多个单词用下划线分割
·函数名 :单词小写,下划线分开
·结构体/枚举/联合名:首字母大写
·宏名 : 全部大写
·变量名 : 单词小写
·面向对象的函数名 : 主+宾 dlist_append();
1.2封装(隔离变化,降低了复杂度)
a.隐藏数据结构
b.隐藏内部函数
b.a在头文件中,放有必要暴露的最小接口
b.b在 *.c文件中,内部函数全部使用static修饰
c.谨慎使用全局变量
全部变量会占用内存空间,共享库的全局变量是按页分配的,哪怕只有一个字节的全部变量也会占用一个页
1.3回调函数
1.4数据的存放
a .bss段 用来存放没有初始化或者初始化为0的全局变量
a.a bss类型的全局变量仅仅占用运行时的内存空间,不占用文件空间
a.b 作为全局变量,在整个程序运行期间,bss数据时一直存在的
b .data段 初始化过的全局变量 (字符串自动放到rodata,其他变量需要加const 修饰)
b.a .data类型的全局变量既占用文件空间,又占用运行内存空间
b.b 作为全局变量,在整个运行期间,data数据一直存在
c .rodata段 read only 存放常量数据
c.a 常量数据不一定存放在.rodata中,可能存放在代码段(.txt)
c.b 保证一个字符串在一个可执行程序员中只有一个备份
c.c rodata在多个进程间是共享的,可以提高空间利用率
c.d 在有的嵌入式设备中,rodata段直接在ROM中,运行时直接读取,XIP技术(execute in place),执行读取,不需要拷贝到RAM中
c.e 常量是不可以修改的
#include <stdio.h>
char* str1 = "HELLO";
int main(){
char* str2 = "HELLO";
printf("%d\t%d\n",(int)&str1[0],(int)&str2[0]);
//打印出的是同一个地址
}
d .txt代码段 存放代码和部分整数常量,是可以执行的
e .stack 用来存放临时变量和函数参数的
f .heap 最灵活的一种内存,生命周期由使用者分配 malloc/free
Linux程序运行时内存空间的分配
niostar@ubuntu:~/chenqian/cTest$ cat /proc/self/maps
08048000-08053000 r-xp 00000000 08:01 655380 /bin/cat
08053000-08054000 r--p 0000a000 08:01 655380 /bin/cat
r--p表示存放的是rodata 有文件名
08054000-08055000 rw-p 0000b000 08:01 655380 /bin/cat
rw-p表示的是bss.data段 有文件名
083e8000-08409000 rw-p 00000000 00:00 0 [heap]
b740e000-b760e000 r--p 00000000 08:01 8179 /usr/lib/locale/locale-archive
b760e000-b760f000 rw-p 00000000 00:00 0
b760f000-b77ae000 r-xp 00000000 08:01 394145 /lib/i386-linux-gnu/libc-2.15.so
b77ae000-b77b0000 r--p 0019f000 08:01 394145 /lib/i386-linux-gnu/libc-2.15.so
b77b0000-b77b1000 rw-p 001a1000 08:01 394145 /lib/i386-linux-gnu/libc-2.15.so
b77b1000-b77b4000 rw-p 00000000 00:00 0
b77c6000-b77c7000 r--p 005e0000 08:01 8179 /usr/lib/locale/locale-archive
b77c7000-b77c9000 rw-p 00000000 00:00 0
b77c9000-b77ca000 r-xp 00000000 00:00 0 [vdso]
r-xp表示的是text数据
b77ca000-b77ea000 r-xp 00000000 08:01 394125 /lib/i386-linux-gnu/ld-2.15.so
b77ea000-b77eb000 r--p 0001f000 08:01 394125 /lib/i386-linux-gnu/ld-2.15.so
b77eb000-b77ec000 rw-p 00020000 08:01 394125 /lib/i386-linux-gnu/ld-2.15.so
bfe17000-bfe38000 rw-p 00000000 00:00 0 [stack]
r--可以读取 w--可以修改 x--可以执行 p/s--是否为贡献
没有文件名的是mmap映射的匿名空间
————————Chapter2 又好又快的code———-
2.1 代码速度又好又快,找一个中间质量值
2.2 消耗时间
分析————–>编码————–>测试——————–>调试
2.3 在编译代码前,有时间的情况下多阅读几次代码
2.4 避免常见错误
a.内存泄漏,对长时间运行的程序消耗危害很大
b.内存越界访问
c.野指针,使用自己释放掉的指针,(正确做法 : free(p); p = NULL;)
d.访问空指针,
空指针不同于未初始化的指针,因为空指针可以确保不指向任何对象或者函数,而未初始化的指针可能指向任何地方e.引用未初始化的变量,编译器会对变量进行不确定的初始化,这是什么可怕的
f.指针运算, p+n = p+n*sizeof(*p)
g. 结构体的成员顺序或者大小发生变化 struct son = { .parent = 1 , .brother = 2 };
h.分配释放不配对
i.返回指向临时变量的指针,栈里面的变量都是临时的,当函数指向完成返回后,相关的变量和参数都是临时的,不要把这些临时变量的指针返回给调用者, char str[]不可以 char* str可以
j. 修改常量,存放在rodata内的存页面的是不可以修改的
k.误解传值和传引用
L.命名冲突,作用于,尽量避免让编译器使用默认规则
M.栈溢出, 嵌入式设备的栈空间很小相对于pc来说
n 误用sizeof ,参数传递过来的char str[]相当于传递指针 ,sizeof(str) = 4;
o 字