为了避免对那些静态链接库或者动态链接库文件大动干戈,我们可以使用ld提供的–wrap选项。
例如,想把所有的malloc函数都作修改,以便让malloc出的内存都是32字节对齐的。
我们可以给ld传选项“wrap=malloc”, 告诉ld,我们将替换名称为malloc的函数。
接着再如下定义一个新的malloc函数:
编译时:gcc -DMAX=32 -o a a.c
相当于在文件a.c中定义:#define MAX 32
为了避免对那些静态链接库或者动态链接库文件大动干戈,我们可以使用ld提供的–wrap选项。
例如,想把所有的malloc函数都作修改,以便让malloc出的内存都是32字节对齐的。
我们可以给ld传选项“wrap=malloc”, 告诉ld,我们将替换名称为malloc的函数。
接着再如下定义一个新的malloc函数:
void * __wrap_malloc( size_t size) {
void* result;
result=memalign(32, size);
return result;
}
可以看到,程序中有个类似库函数名称的__wrap_malloc。
ld在遇到__wrap选项后,会使用__wrap_malloc函数名替换所有对malloc的调用。
并以此实现替换的作用。
那麽,如果还向调用原函数怎么办呢?
可以使用__real_malloc,这个函数名称就对应了原来的malloc。
每次调用malloc时都打印生成的指针地址。
void * __wrap_malloc( size_t size) {
void* result;
result= __real_malloc( size);
printf("Malloc: allocate %d byte mem, start at %p", size, result);
return result;
}
#include <stdio.h>
#include <stdlib.h>
void * __wrap_malloc( size_t size) {
void* result;
//result= __real_malloc( size); result = memalign(32, size);
printf("Malloc: allocate %d byte mem, start at %p", size, result);
return result;
}
int main ()
{
int i,n;
char * buffer;
printf ("How long do you want the string? ");
//scanf ("%d", &i); i = 200;
buffer = (char*) malloc (i+1);
if (buffer==NULL) exit (1);
for (n=0; n<i; n++)
buffer[n]=rand()%26+'a';
buffer[i]='\0';
printf ("Random string: %s\n",buffer);
free (buffer);
return 0;
}
$gcc test_malloc.c -Wl,--wrap=malloc
GCC 的 -I 参数可以用来指定头文件目录,当前目录和缺省目录(/usr/include && /usr/local/include)不用指定。
另外,-include 用来包含某个头文件,但一般情况下因为已经在源码里用 #include 指令实现了,所以这个很少用。
-I dir | 在头文件的搜索路径列表中添加dir目录 |
-L dir | 在库文件的搜索路径列表中添加dir目录 |
[root@localhost Gcc] Gcc hello_sq.c –L /root/workplace/Gcc/lib –lsunq –o hello_sq
需要注意的是,“-I dir”和“-L dir”都只是指定了路径,而没有指定文件,因此不能在路径中包含文件名。
Gcc总体选项列表
后 缀 名 | 所对应的语言 |
-S | 只是编译不汇编,生成汇编代码 |
-E | 只进行预编译,不做其他处理 |
-g | 在可执行程序中包含标准调试信息 |
-o file | 把输出文件输出到file里 |
-v | 打印出编译器内部编译各过程的命令行信息和编译器的版本 |
-I dir | 在头文件的搜索路径列表中添加dir目录 |
-L dir | 在库文件的搜索路径列表中添加dir目录 |
-static | 链接静态库 |
-llibrary | 连接名为library的库文件 |
· “-I dir”
正如上表中所述,“-I dir”选项可以在头文件的搜索路径列表中添加dir目录。由于Linux中头文件都默认放到了“/usr/include/”目录下,因此,当用户希望添加放置在其他位置的头文件时,就可以通过“-I dir”选项来指定,这样,Gcc就会到相应的位置查找对应的目录。
比如在“/root/workplace/Gcc”下有两个文件:
#include
int main()
{
printf(“Hello!!\n”);
return 0;
}
#include
这样,就可在Gcc命令行中加入“-I”选项:
[root@localhost Gcc] Gcc hello1.c –I /root/workplace/Gcc/ -o hello1
这样,Gcc就能够执行出正确结果。
小知识
在include语句中,“<>”表示在标准路径中搜索头文件,““””表示在本目录中搜索。故在上例中,可把hello1.c的“#include”改为“#include “my.h””,就不需要加上“-I”选项了。
· “-L dir”
选项“-L dir”的功能与“-I dir”类似,能够在库文件的搜索路径列表中添加dir目录。例如有程序hello_sq.c需要用到目录“/root/workplace/Gcc/lib”下的一个动态库libsunq.so,则只需键入如下命令即可:
[root@localhost Gcc] Gcc hello_sq.c –L /root/workplace/Gcc/lib –lsunq –o hello_sq
需要注意的是,“-I dir”和“-L dir”都只是指定了路径,而没有指定文件,因此不能在路径中包含文件名。
另外值得详细解释一下的是“-l”选项,它指示Gcc去连接库文件libsunq.so。由于在Linux下的库文件命名时有一个规定:必须以lib三个字母开头。因此在用-l选项指定链接的库文件名时可以省去lib三个字母。也就是说Gcc在对”-lsunq”进行处理时,会自动去链接名为libsunq.so的文件。
(3)优化选项
Gcc可以对代码进行优化,它通过编译选项“-On”来控制优化代码的生成,其中n是一个代表优化级别的整数。对于不同版本的Gcc来讲,n的取值范围及其对应的优化效果可能并不完全相同,比较典型的范围是从0变化到2或3。
不同的优化级别对应不同的优化处理工作。
如使用优化选项“-O”主要进行线程跳转(Thread Jump)和延迟退栈(Deferred Stack Pops)两种优化。
使用优化选项“-O2”除了完成所有“-O1”级别的优化之外,同时还要进行一些额外的调整工作,如处理器指令调度等。
选项“-O3”则还包括循环展开和其他一些与处理器特性相关的优化工作。
虽然优化选项可以加速代码的运行速度,但对于调试而言将是一个很大的挑战。因为代码在经过优化之后,原先在源程序中声明和使用的变量很可能不再使用,控制流也可能会突然跳转到意外的地方,循环语句也有可能因为循环展开而变得到处都有,所有这些对调试来讲都将是一场噩梦。所以笔者建议在调试的时候最好不使用任何优化选项,只有当程序在最终发行的时候才考虑对其进行优化。
静态链接库其实就可以看成是 *.o 文件的简单打包:
ar -cr libtest.a test.o 或: ar -cr libtest.a test.cpp
-r 选项是必须的,表示插入到备份文件,并且有则替换 -c 表示创建备份文件
、编译目标代码时 ”-Wl,-rpath,” 指定的动态库搜索路径(当指定多个动态库搜索路径时,路径之间用冒号”:”分隔。);
2、环境变量 LD_LIBRARY_PATH 指定的动态库搜索路径;
-pedantic //检查代码是否符合 ANSI/ISO 标准: -Wall //输出警告信息 -Wextra //输出更多的警告信息 -Weffc++ //检查是否符合 《Effective C++》这本书中提到的标准 -w //关闭所有警告
-g //在编译时生成原生格式的调试符号信息,可以使用 gdb 或 ddx 等调试器调试。-g 分为三个级别,默认为 -g2,其中 -g3 除包含 -g2 中的所有调试信息外,还包含源代码中定义的宏。 -ggdb //在编译时生成 gdb 专用格式的调试符号信息,信息更为丰富,但只能使用 gdb 调试,而不能使用其它调试器。级别设定与 -g 基本相同。 -gdwarf //如果升级 GCC 之后,发现 GDB 不能用了,那么在编译的时候加上 -gdwarf 选项试一下,如果还不行,再使用 -gdwarf-2 试试。 -p //将剖析(Profiling)信息加入到最终生成的二进制代码中,生成可以被通用剖析工具(Prof)能够识别的统计信息,它对于找出程序瓶颈很有帮助。生成后的可执行文件要运行一次,才能生成剖析文件,默认文件名是 gmon.out。 -pg //生成只有 GNU 剖析工具(Gprof)才能识别的统计信息。 -save-temps //保存编译过程中生成的一系列中间文件。 -On //n 可以为 0~3,默认为 1,数字越大优化越高,一般使用 -O2 可以在优化长度、编译时间和代码大小之间取得较好平衡,开发调试建议使用 -O0 -Os //相当于 -O2.5,使用了所有 -O2 的优化选项,但却没有使用增加大小。也就是说,相对于 -O2,能减少一点可执行文件的大小。 -s //从执行文件中删除符号表与重定向信息,以减少执行文件的大小。跟直接编译之后,使用 strip 命令减小文件大小效果一致