重拾C语言基础知识
从实习到工作两年多的时间了,虽然感觉学到了很多知识,但是事实上却将立足之本的基础知识给忘了个精光。也许跟自己没有出去找工作有关,没有好好的将C语言的基础牢牢掌握。
从现在开始吧!好好的重温基础,做一名合格的程序猿!!!!
题目一 参数传递的值传递和其它传递
- void GetMemory( char *p)
- {
- p = (char *) malloc( 100 );
- strcpy( p, "hello world" );
- }
- void main(void)
- {
- char *str=NULL;
- GetMemory(str);
- puts(str);
- }
这个程序是否有错?
从main函数开始,可以看到首先是定义了一个char类型的指针str,然后调用了GetMemory函数,此函数的参数是char 类型的指针。当函数中运行
p = (char *) malloc( 100 );
的时候,是把分配的地址赋值给了P,而此时p所指向的地址和str所指向的地址并不同了。所以整个操作的过程中实际上进行的是值传递而不是地址的传递。
那么进一步思考这个问题的话,我们可以通过地址传递和引用传递的方式进行改进程序。
题目二 编译器相关volatile
编译器优化常用的方法有:将内存变量缓存到寄存器;调整指令顺序充分利用CPU指令流水线,常见的是重新排序读写指令。volatile总是与优化有关,编译器有一种技术叫做数据流分析,分析程序中的变量在哪里赋值、在哪里使用、在哪里失效,分析结果可以用于常量合并,常量传播等优化,进一步可以消除一些代码。但有时这些优化不是程序所需要的,这时可以用volatile关键字禁止做这些优化。
volatile的本意是“易变的” 因为访问寄存器要比访问内存单元快的多,所以编译器一般都会作减少存取内存的优化,但有可能会读脏数据。使用了volatile之后,每次在读取数据的时候都是从变量的地址处读取,而不是从cache中或者寄存器的备份中读取。
基于这种变量的特殊性,那么就应该合理使用,常见的应用场景:
1.中断服务程序中修改的供其它程序检测的变量需要加volatile
2.多任务环境下各任务间共享的标志应该加volatile
3.存储器映射的硬件寄存器通常也要加voliate,因为每次对它的读写都可能有不同意义
另:linux kernel中的内存屏障https://www.kernel.org/doc/Documentation/memory-barriers.txt
题目三 C语言中内存分布及程序运行中(BSS段、数据段、代码段、堆栈)
BSS段:(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。BSS是英文Block Started by Symbol的简称。BSS段属于静态内存分配。
- RO是程序中的指令和常量
- RW是程序中的已初始化变量
- ZI是程序中的未初始化的变量
- RO就是readonly,
- RW就是read/write,
- ZI就是zero
所谓ARM映像文件就是指烧录到ROM中的bin文件,也成为image文件。以下用Image文件来称呼它。
Image文件包含了RO和RW数据。
之所以Image文件不包含ZI数据,是因为ZI数据都是0,没必要包含,只要程序运行之前将ZI数据所在的区域一律清零即可。包含进去反而浪费存储空间。