----------------------------------------
查找,查看连接的库位置: gcc -v
预处理过程:gcc -E, 可以看到头文件及宏展开后的形态。
cpp -dD 可以显示宏定义过程。 -dM 还能显示预定义宏。 cpp -dM /dev/null 显示纯系统定义宏
虽然我不能确定gcc 是否调用了cpp 来进行预处理(也许不是), 但把gcc 换成cpp, 再加上-dD 选项
确实可以达到目的。然后你可以按提示直接去浏览文件,以解除心中的疑惑!
什么都不用动,把gcc 换成 cpp, 加上-g3 选项,可以看到细节。
还有一个有用的技巧。向gcc 传递了-Wa,-alh 参数,生成了汇编列表文件,使我很欣慰!
不仅.s文件,.c 文件也可以,令我惊讶。用法很简单。有什么用呢?有用,...慢慢再说。
----------------------------------------
gcc -g3 能够使我们在gdb 中看到宏定义和宏值。
gdb 中: 对宏的用法
p XXXX
info macro XXXX
macro expand XXXX
----------------------------------------
gcc 生成prof. gcc -pg
man gcc 有对-pg 选项的说明, gcc --help 没有对该项的说明
需要运行程序,正常退出,才能生成gmon.out, 供gprof 分析
gprof (默认为-p -q) -p 统计,本职功能, -q call graph, -b 简短的,不输出对各参数的解释。
-A[symspec], 只关联指定函数
用法举例:
gprof ./test gmon.out -b
生成调用图片:
gprof ./test | gprof2dot.py -n0 -e0 | dot -Tpng -o output.png
gprof2dot 默认是部分函数调用图 -n0.5, 即影响小于5%的函数就不显示了。
-n0 -e0 显示全部函数调用,当然这样可能因为内容太多,显示比较混乱。
-s 选项, 不显示诸如模板,函数入口参数等,使函数名称显示更加简洁。
由以上命令可以解决程序中的符号定位问题。
gcc -M -MP -MF -MD -MT 是什么意思?
gcc -M 不是输出预处理结果,而是输出源文件的依赖关系,包括include 的头文件,
gcc -MF abc.Tpo 把依赖关系输出到指定的输出文件, 否则会输出到屏幕上, abc.Tpo是输出文件名
gcc -MP 对每一个头文件也生成 target.,这样当make 的时候,每个头文件必需存在,编译更严谨
上面三项常连用。
gcc -MD: 相当于 -M -MF, 使用了默认文件名--目标文件名加.d , 保存依赖关系
可见,它们都是为了target 的依赖关系而生。
gcc -MT: 指定一个新的target 名。
----------------------------------------
消除 warning: "unused parameter xxxx"警告
----------------------------------------
如下定义一个宏即可:
#define UNUSED(x) (void)x
举例:
UNUSED(argc);
UNUSED(argv);
----------------------------------------
在64位机器上,整形数不能直接转化为指针。提示如下警告:
cast to pointer from integer of different size
----------------------------------------
有时候由于参数定义等原因确实需要强制转换,如下形式可用。
先转为long, 再转为指针。
(void *)(long)int_value
~
----------------------------------------
判断gcc 到底连接的是哪一个库,是动态库还是静态库,库的全路径是什么?
我目前采用的办法是strace.
对于exe 或 或 so, 判断其动态库依赖关系可以用ldd,
例如:
[/pts/1@hjj ~/work/cube_httpd]$ ldd httpd
linux-vdso.so.1 => (0x00007fff0fdff000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x0000003a13c00000)
libc.so.6 => /lib64/libc.so.6 (0x0000003a13800000)
/lib64/ld-linux-x86-64.so.2 (0x0000003a13400000)
------------------------------------------------------------
问题. gcc 版本不一致出现的问题,查看gcc 版本,strings 命令
------------------------------------------------------------
./app_ref: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by ./app_ref)
软件编译时使用了较高版本的glibc: 要求glibc_2.14, 这是是gcc 4.6 编译的.
当前系统的glibc版本太低,
查看当前的glibc.
$ strings /lib64/libc.so.6 |grep -i glibc
GLIBC_2.2.5
GLIBC_2.2.6
GLIBC_2.3
GLIBC_2.3.2
GLIBC_2.3.3
GLIBC_2.3.4
GLIBC_2.4
GLIBC_2.5
GLIBC_2.6
GLIBC_2.7
GLIBC_2.8
GLIBC_2.9
GLIBC_2.10
GLIBC_2.11
GLIBC_2.12
GLIBC_PRIVATE
glibc 2.12
*** glibc detected *** %s: %s: 0x%s ***
发现最高支持到glibc 2.12.
这个是gcc 4.4 支持到的版本
降低app_ref 的gcc, 或升级本系统gcc, 问题可以解决.
----------------------------------------
volatile 变量: 禁止编译器优化选项。
----------------------------------------
例如:int i; for(i=0;i<1000;i++);
被优化为i=1000
mem[2]=0x1;mem[2]=0x2;mem[2]=0x3;
被优化为mem[2]=0x3;
大部分优化是可行的,它缩短了执行时间,同样达到了效果。但有时不是我们需要的。
void main(int argc,char *argv[])
{
int i = 10;
int a = i;
printf("i=%d",a);
//下面汇编语句的作用就是改变内存中i的值,但是又不让编译器知道
__asm
{
mov dword ptr[ebp-4],20h
}
int b = i;
printf("i=%d",b);
}
如上代码,编译器可能把b 直接优化成10. 因为编译器可能把i 读入寄存器中,例如%edx
然后把%edx 付给内存a, 又付给内存b, 它不知道内存i 内容已经变了。这不是我们所要的
告诉编译器i 是volatile, 编译器将不对i进行优化,将忠实于代码执行流程。