PHP源码初探之GCC简单介绍(二)
2013-11-27 01:04
288 查看
一、Warning Options in -Wall 警告信息 -Wall表示全部内容,在具体的使用过程中,我们还可以精确的使用警告提示信息
1、-Wcomment 检测注释是不是嵌套了,C语言规定你的注释是不能嵌套的
2、 -Wformat 检测printf和sanf里面的传值是否有误
3、 -Wunused 检测是不是有些声明了但并没有使用的变量
4、 -Wimplicit 如果你使用了一个函数,但是这个函数你并没有声明;最常见的是你使用了某个函数,但并没有引用函数库
5、 -Wreturn-type 如果你函数没有声明返回,但你没有使用void
上面的错误往往是常见的错误,这就是-Wall为什么这么有用的原因。它产生的错误,我们必须严格的重视。
二、使用预处理(Preprocessor)
看看下面的例子:-D就是预处理器
有的时候,我们需要Debug,这里就需要使用-E,这里不需要编译,只是希望看见过程
有时候,我们需要查看中间结果,我们就需要把临时结果保存下来,供我们分析
hello.i保存的是预处理结果
hello.s先转换成汇编语言
hello.o在生成目标文件(机器码)
二、gcc中调试代码---gdb
这里我们就需要知道错误并调试,这里需要我们需要产生codedump,但codedump是默认关闭的,使用
这时候就可以使用gdb调试程序
关于gdb的详细用法,后面会有专门的章节
三、gcc编译优化代码
我们编译程序,根据我们程序员自己的思路;但是gcc编译器会根据cpu的特性产生高的代码质量,提高程序的可执行速度。
gcc是一个优化的编译能力很强的编译器,但这格优化是个很复杂的程序,对于程序的实现,对于底层都有很多方法完成,但是那种方法最好,这就是编译器的一个重要指标。
gcc有三个重要的优化代码:
1、Common Subexpression Elimination(CSE)公用子表达式消除
它的主要思想,有点像缓存,就是重新利用;我们在计算的时候有很多中间结果,它就将这些结果保存下来,下次直接调用。把gcc的优化开关打开,就可以自动使用了。看一个例子:
2、Function Inlingind(FL) 函数调用函数(内嵌)
一个函数被调用,额外的开销是必须的,如:压栈、出栈
如果函数不大,执行频繁就可以使用内嵌,c语言使用in-line标识,如:代码
3、Loop Unrolling 循环判断
看码
四、机器码层级的优化,这里就需要使用gcc传递参数的形式
1、-OLEVEL 0~3 想使gcc优化,使用此参数,优化等级逐步提交,0是不优化
优化等级越高,代价可能越大,执行效率并不是优化等级越高执行效率越高。
优化等级越高机器更改你的代码就越多,Dbug的难度越高,如果不优化就比较顺畅
2、-O2,在生产环境的时候就可以了,在调试的时候就打开-O1
看例子:
1、-Wcomment 检测注释是不是嵌套了,C语言规定你的注释是不能嵌套的
#include <stdio.h> int main(void) { /* /*this is a test*/ printf("Hello world!\n") */ return 0; } //这就会出现嵌套注释的错误提示-Wcomment- Wcomment就是检查上面的错误的,我们可以使用宏定义
#include <stdio.h> int main(void) { #if 0 /*this is a test*/ printf("Hello World\n"); #endif return 0; }
2、 -Wformat 检测printf和sanf里面的传值是否有误
printf("%f", 123)
3、 -Wunused 检测是不是有些声明了但并没有使用的变量
4、 -Wimplicit 如果你使用了一个函数,但是这个函数你并没有声明;最常见的是你使用了某个函数,但并没有引用函数库
5、 -Wreturn-type 如果你函数没有声明返回,但你没有使用void
上面的错误往往是常见的错误,这就是-Wall为什么这么有用的原因。它产生的错误,我们必须严格的重视。
二、使用预处理(Preprocessor)
#include <stdio.h> int main(void) { int i; #define MAX 1024 + 128 /*宏定义*/ /*this is a test*/ printf("Hello World!\n"); i = MAX * 2; /*== 1024 + 128 * 2*/ printf("%d\n", i); return 0; }在c语言执行的过程中,首先会找#预处理,将其全部替换;它只是简单的替换,是什么就替换什么
#include <stdio.h> int main(void) { #ifdef TEST printf("Test mode\n"); #endif printf("Running...\n"); return 0; } $ gcc -Wall -DTEST dtest.c -o dtest /*-D定义了TEST就会执行,这在调试的时候非常有用*/ $ gcc -Wall dtest.c -o dtest /*就不会执行宏定义的内容*/在上面的例子中我们必须明白,-DNAME=VALUE的概念,如果没有定义值,默认是1;那么#ifdef 1永远就是成立的了
看看下面的例子:-D就是预处理器
#include <stdio.h> int main(void) { printf("%d\n", NUM); return 0; } gcc -Wall -DNUM=1234 dtest.c -o dtest gcc -Wall dtest.c -o dtest /*就会报错*/ gcc -Wall -DNUM="1+2" dtest.c -o dtest /*只是简单的替换*/
有的时候,我们需要Debug,这里就需要使用-E,这里不需要编译,只是希望看见过程
#define TEST "Hello, tianhu.peng!" const char str[] = TEST gcc -E etest.c /*就会显示*/
# 1 "etest.c" # 1 "<built-in>" 1 # 1 "<built-in>" 3 # 162 "<built-in>" 3 # 1 "<command line>" 1 # 1 "<built-in>" 2 # 1 "etest.c" 2 const char str[] = "Hello, tianhu.peng!";通过E只会调用预处理程序
有时候,我们需要查看中间结果,我们就需要把临时结果保存下来,供我们分析
gcc -Wall -c hello.c -save-temps hello.c上面的程序会产生3个文件,hello.i,hello.s,hello.o
hello.i保存的是预处理结果
hello.s先转换成汇编语言
hello.o在生成目标文件(机器码)
二、gcc中调试代码---gdb
#include <stdio.h> int a(int *p) int main(void) { int* p = 0; // 空指针 return a(p); } int a(int *p) { int y = *p; //是不能访问空指针 return y; }运行
$ gcc -Wall -g test.c // -g表示将变量、行号等信息放在一个符号表中;这里不会报错,因为编译中运行时的错误gcc是不能检测的:Segmentation fault错误
这里我们就需要知道错误并调试,这里需要我们需要产生codedump,但codedump是默认关闭的,使用
ulimit -c // 0表示不允许,开启来需要 ulimit -c unlimited再次执行./a.out就会产生coredumpe,一个名称为core.123..的文件
这时候就可以使用gdb调试程序
gdb a.out core.123... //提示清晰的告诉你错误的地方 #0 0x000000000040049e in a (p=0x0) at null.c:12 12 int y = *p;
关于gdb的详细用法,后面会有专门的章节
三、gcc编译优化代码
我们编译程序,根据我们程序员自己的思路;但是gcc编译器会根据cpu的特性产生高的代码质量,提高程序的可执行速度。
gcc是一个优化的编译能力很强的编译器,但这格优化是个很复杂的程序,对于程序的实现,对于底层都有很多方法完成,但是那种方法最好,这就是编译器的一个重要指标。
gcc有三个重要的优化代码:
1、Common Subexpression Elimination(CSE)公用子表达式消除
它的主要思想,有点像缓存,就是重新利用;我们在计算的时候有很多中间结果,它就将这些结果保存下来,下次直接调用。把gcc的优化开关打开,就可以自动使用了。看一个例子:
x = cos(v) * (1+sin(u/2)) + sin(w) * (1 -sin(u/2)) // 这里sin(u/2)保存一次就行了 // 改后的代码 t = sin(u/2) // 这里只计算一次 x = cos(v) *(1+t) + sin(w) * (1-t) // 上面的优化技术就是CSE
2、Function Inlingind(FL) 函数调用函数(内嵌)
一个函数被调用,额外的开销是必须的,如:压栈、出栈
如果函数不大,执行频繁就可以使用内嵌,c语言使用in-line标识,如:代码
double sq(double x) // 还可以使用 inline double sq(double x) //如果打开开关就会自动的加上inline { return x*x; } sum = 0.0; for (i = 0; i < 10000000; i++) { sum +=sq(i+0.5); } // 上面最大的开销是sq的压栈与出栈 上面改为 for (i = 0; i < 10000000; i++) { t = i + 0.5; sum += t * t; }
3、Loop Unrolling 循环判断
看码
for (i = 0; i< 100; i++) { printf("%d", i); //这里的i,每次循环都会判断是不是<100;如果是+1反之退出循环 } // 如果我们需要加速循环 // 我们可以这样 print(1); print(2); //.. // 这种方法肯定比上面的快很多,如果可以并发更快;这就是Loop Unroling的思想;它提高了速度,增加了大小如果是不能指定大小的化,gcc会把上面的代码改写为下面的代码
for (i = 0; i < (n%2); i++) { y[i] = i; } for (; i+1 < n; i+=2) { y[i] = i; y[i+1] = i+1; }我只是初学者,知道有这个概念,如果你想深入的研究,可以专门研究
四、机器码层级的优化,这里就需要使用gcc传递参数的形式
1、-OLEVEL 0~3 想使gcc优化,使用此参数,优化等级逐步提交,0是不优化
优化等级越高,代价可能越大,执行效率并不是优化等级越高执行效率越高。
优化等级越高机器更改你的代码就越多,Dbug的难度越高,如果不优化就比较顺畅
2、-O2,在生产环境的时候就可以了,在调试的时候就打开-O1
看例子:
#include <stdio.h> double powern(double d, unsigned n) // d的n次方 { double x = 1.0; unsigned j; for(j=1; j<=n; j++) x *= d; return x; } int main(void) { double sum = 0.0; unsigned i; for (i = 1; i <= 100000000; i++) { sum += powern(i, i%5); } printf("sum = %g\n", sum); // g表示很大的数 return 0; }我们用几种级别测试
gcc -Wall -O0 test.c -o o0 // 没有优化 time ./o0 sum = 4e+38 real 0m1.391s user 0m0.558s sys 0m0.002s gcc -Wall -O1 test.c -o o1 time ./o1 real 0m0.622s user 0m0.158s sys 0m0.001s gcc -Wall -O2 test.c -o o2 time ./o2 real 0m0.331s user 0m0.173s //时间并没有o1低 sys 0m0.000s gcc -Wall -O3 test.c -o o3 time ./o3 real 0m0.325s user 0m0.200s //时间最慢 sys 0m0.001s gcc -Wall -O3 -funroll-loops test.c -o o4 time ./o4real 0m0.386s user 0m0.160s // 耗时减少 sys 0m0.000s
相关文章推荐
- PHP源码初探之GCC简单介绍(-)
- PHP源码初探之GCC简单介绍(三)
- Monkey源码分析1—Monkey简单介绍
- php 单例模式详细介绍及实现源码
- php中$this->的用法简单介绍
- [Java] 【源码】新手初探java网络编程——socket接口实现简单的客户机/服务器程序
- PHP分页初探 一个最简单的PHP分页代码实现
- php文件下载功能简单源码示例
- PHP分页初探 一个最简单的PHP分页代码实现
- Linux(6.4)+Nginx(1.4.1)+Mysql(5.6.12)+Php(5.5.0)源码编译安装 环境介绍
- 比较简单实用的PHP无限分类源码分享(思路不错)
- PHP实现简单聊天室(附源码)第1/2页
- PHP内核--源码安装与介绍
- PHP在浏览器上跟踪调试的方法以及使用ChromePhp、FirePHP的简单介绍
- 简单介绍PHP获取文件属性方法
- GLFW简单工程源码介绍
- php -- 魔术常量 简单介绍
- php网站制作(1)-简单介绍,开发环境搭建
- php操作Mysql简单介绍:连接mysql|打开数据库|查询|关闭mysql
- cocos2d-x源码包简单介绍