[Mac 10.7.1 Lion Intel-based x64 gcc 4.2.1]
Q: 如何让编译的文件可以被gdb调试?
A: 可以加入-g参数。如下代码,保存为hello.c:
#include <stdio.h> int main() { printf("hello world!\n"); return 0; }编译 gcc hello.c -o hello得到hello.
使用 gdb hello进入调试,输入list:
可以看到提示没有符号被加载,这说明上面的编译命令没有加入调试信息,不能被gdb正常调试。
加入-g参数重新编译 gcc -g hello.c -o hello得到文件hello.
gdb hello进入调试,输入list:
可以看到,此时已经可以看到源代码了,接着就可以调试了。
Q: 如何编译程序能让gprof工具使用?
A: 使用-p参数。不过根据bug列表,intel架构的mac系统不能正常运行gprof, 以后将在ubuntu下将这个例子写出来。
Q: 如果源代码的扩展名不是gcc默认支持的扩展名,那么编译会出现什么情况?
A: 将上面的hello.c复制一个为hello.xichen,使用gcc -o hello hello.xichen编译:
可以看到出现了问题;可以使用-x参数将文件当成指定类型的文件来编译:
gcc -x c hello.xichen -o hello是将hello.xichen当成c代码编译:
可以看出已经正确编译了; -x参数后面可以跟随c, c++等类型名, 也可以跟随none来关闭指定为特定类型文件编译, 具体请参照gcc帮助文档。
Q: 如果需要测试代码是否符合ansi标准,怎么办?
A: 可以使用-ansi参数。如果是c代码,它对于不遵循c90标准的代码将出现编译问题。
对于//作为注释,从c99才开始支持,用此作为测试。
#include <stdio.h> int main() { // c99 support // style comment printf("hello world!\n"); return 0; }保存为hello.c:
gcc -ansi -o hello hello.c编译:
使用gcc -o hello hello.c编译:
可以看到,这样就没有问题。
Q: c语言有不同的标准,那么设定遵循哪种标准使用什么参数?
A: 可以使用-std=参数格式,可以跟随c99, gnu99等参数。
Q: 如何禁止将某些关键字当做关键字?
A: 可以使用-fno-asm参数来禁止asm, inline, typeof当做关键字。如下代码,保存为hello.c:
#include <stdio.h> inline int add(int a, int b) { return a + b; } int main() { printf("hello world!\n"); return 0; }使用gcc -fno-asm hello.c -o hello编译:
可以看到出现了编译错误;使用gcc hello.c -o hello编译:
Q: 有时,有的编译器将char默认当做有符号的,有的当做无符号的,用编译器参数可以实现*控制么?
A: 是的。可以使用-funsigned-char或者-fno-signed-char来将char自动当做unsigned类型;类似的,用-fsigned-char或者-fno-unsigned-char来将char自动当做signed类型。例子如下,代码保存为unsigned_signed_char.c:
#include <stdio.h> int main() { char ch = 0xFF; if(ch < 0) printf("char is signed...\n"); else printf("char is unsigned...\n"); return 0; }使用gcc unsigned_signed_char.c -o unsigned_signed_char编译运行:
使用gcc unsigned_signed_char.c -o unsigned_signed_char -funsigned-char编译运行:
使用 gcc unsigned_signed_char.c -o unsigned_signed_char -fsigned-char来编译运行:
Q: 如果有的时候在一个文件中忘记包含了头文件,如何用编译参数插入头文件呢?
A: 可以使用-include参数。代码如下,保存为no_header.c:
int main() { fprintf(stdout, "no header file\n"); return 0; }使用gcc no_header.c -o no_header编译:
可以看到,编译出错了;改用gcc no_header.c -o no_header -include /usr/include/stdio.h编译:
运行ok:
同样,可以使用-DXXX或者-DXXX=YYY或者-UXXX或者-undef来定义宏获取取消定义宏(XXX表示宏名, YYY表示宏定义的字符串).
Q: 有时,有个宏在另外一个文件中,想把它的值作用到另一个文件中,如何做?
A: 可以使用-imacros 参数; -imacros后面跟着需要包含的宏名的文件。如下代码,保存为imacros.h:
#ifndef IMACROS_H #define IMACROS_H #define N 100 double add(double, double); #endif如下代码,保存为imacros.c(它和上面的imacros.h在同一个目录下):
#include <stdio.h> int add(int, int); int main() { int i = N; printf("i is %d\n", i); return 0; }可以看到imacros.c文件中的N没有被定义,imacros.h中有它的宏定义。使用gcc imacros.c -o imacros -imacros imacros.h编译:
可以看到编译ok,且imacros.h中的add函数声明和imacros.c中的add函数声明不一致的问题也没有任何警告,因为-imacros仅仅将imacros.h文件中的宏进行处理,其它没有处理。
运行结果:
修改imacros.c代码如下:
#include <stdio.h> #include "imacros.h" int add(int, int); int main() { int i = N; printf("i is %d\n", i); return 0; }采用gcc imacros.c -o imacros编译:
可以看到,编译出错了,就是因为add声明不一致导致的;这里就可以看出-imacros参数的作用了。
Q: 如果有的时候,为了方便管理,将一些头文件移动到另一个目录,代码中的头文件路径不想用绝对路径,命令行参数该如何设置呢?
A: 可以使用-I参数来实现添加额外头文件路径的方式。如下代码,保存为include_folder.c:
#include <stdio.h> int main() { fprintf(stdout, "hello\n"); return 0; }在hello.c的同目录下创建如下文件stdio.h:
#ifndef STDIO_H #define STDIO_H #endif它基本没什么用途。
如果使用gcc include_folder.c -o include_folder编译没有任何问题。
如果使用gcc include_folder.c -o include_folder -I.编译:
可以看出,编译出了问题,因为-I.编译参数将本目录加入了头文件搜索路径, 而且是优先在-I指定的路径下查找,include_folder.c包含了stdio.h头文件,且优先在本目录下查找,包含了一个没有任何用途的头文件,导致了后面的编译错误。和-I参数对于头文件路径修改类似的,还有-idirafter, -iprefix, -iwithprefix, -iwithprefixbefore参数。
Q: 如果一个makefile中在当时必须使用-I来包含指定的头文件路径,但是后来因为一些原因又不能继续使用,有命令可以解决这个问题么?
A: 是的。可以使用-I-来取消使用-I参数指定的额外的头文件路径,不过这个参数形式以后可能会废弃,建议采用-Iquote来代替它。如上面的代码,使用gcc include_folder.c -o include_folder -I. -I-或者gcc include_folder.c -o include_folder -I. -iquote都可以正确编译。
Q: 如果不想使用系统的头文件,想直接使用自己编写的头文件,这些头文件被存储在另一个目录下,怎么办?
A: 如下代码nostdinc.c:
#include <stdio.h> #include <stdlib.h> int main() { int i = NOSTDINC; return 0; }nostdinc.c同目录下有个头文件stdio.h:
#ifndef STDIO_H #define STDIO_H #define NOSTDINC 99 #endif使用gcc nostdinc.c -o nostdinc -I. -nostdinc编译:
可以看出,使用了-nostdinc参数,编译器将不在系统头文件路径下搜索, -I.将使得它在本目录下搜索,结果没找到stdlib.h头文件,报错了;可以去掉-nostdinc参数选项,使用gcc nostdinc.c -o nostdinc -I.编译即可:
或者nostdinc.c源代码中将对stdlib.h头文件的包含代码去掉也可以。
Q: 有时需要对源代码进行预处理,但是其中的注释被删除了,对于分析预处理后代码可能有影响,如何让预处理过程不删除注释?
A: 可以使用-C参数来实现,它一般都和-E参数搭配使用。如下代码simple_hello.c:
int main() { // just write something return 0; }使用gcc -E simple_hello.c预处理,得到内容:
# 1 "simple_hello.c" # 1 "<built-in>" # 1 "<command-line>" # 1 "simple_hello.c" int main() { return 0; }可以看到,注释被删除了。
如果采用gcc -C -E simple_hello.c预处理,得到如下内容:
# 1 "simple_hello.c" # 1 "<built-in>" # 1 "<command-line>" # 1 "simple_hello.c" int main() { // just write something return 0; }可以发现注释依然存在。
Q: 有时我需要查看一个源代码的依赖关系,如何查看?
A: 可以使用-M参数来获得。例如,如下代码,保存为hello.c:
#include <stdio.h> int main() { printf("hello, xichen\n"); return 0; }使用gcc -M hello.c得到内容:
hello.o: hello.c /usr/include/stdio.h /usr/include/sys/cdefs.h \ /usr/include/sys/_symbol_aliasing.h \ /usr/include/sys/_posix_availability.h /usr/include/Availability.h \ /usr/include/AvailabilityInternal.h /usr/include/_types.h \ /usr/include/sys/_types.h /usr/include/machine/_types.h \ /usr/include/i386/_types.h /usr/include/secure/_stdio.h \ /usr/include/secure/_common.h可以看出,hello.c的依赖关系。
类似的还有-MD, -MM, -MMD参数。
Q: 如果希望将一个编译选项传递给gcc内部调用的汇编程序或者链接程序,如何传递?
A: 可以使用-Wa,option的方式将option传递给汇编程序;可以使用-Wl,option的方式将option传递给链接程序。
Q: 有时,我需要生成stabs格式的调试信息,如何生成?
A: 可以使用-gstabs命令得到,但是它不会生成gdb调试信息,所以无法再用gdb对生成的可执行文件进行调试。类似的编译参数还有-gstabs+, -ggdb.
Q: 如果希望使用静态链接或者动态链接,或者生成一个共享库,使用什么参数?
A: 可以使用-static或者-shared参数。但是,在mac系统上,-static基本没什么用,-shared参数它不支持。
Q: 如何希望体验古老的c语言的特性,可以使用什么参数?
A: 可以使用-traditional参数。具体的例子笔者也写不出来,写了几个看起来很古老的语法,结果gcc都正常给编译通过了。
Q: 如果需要生成针对某个平台的优化代码,如何办?
A: 可以使用-O相关的参数进行优化,也可以使用-mtune=cpu_type进行具体平台优化。
Q: 如果需要不显示警告信息或者显示所有能显示的警告信息,如何办?
A: 可以使用-w参数或者-Wall参数。如下代码,保存为warning.c:
#include <stdio.h> void main() { int i; printf("hello, xichen\n"); }使用gcc warning.c -o warning编译:
使用gcc warning.c -o warning -Wall编译:
可以看出,包括i没有被使用的警告也被显示出来;
使用gcc warning.c -o warning -w编译:
可以看到没有任何警告信息显示了。
xichen
2012-5-19 22:26:32