gcc编译命令----小话c语言(14)

时间:2023-01-13 11:43:19

[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:

gcc编译命令----小话c语言(14)

可以看到提示没有符号被加载,这说明上面的编译命令没有加入调试信息,不能被gdb正常调试。

加入-g参数重新编译  gcc  -g  hello.c  -o  hello得到文件hello.

gdb  hello进入调试,输入list:

gcc编译命令----小话c语言(14)

可以看到,此时已经可以看到源代码了,接着就可以调试了。


Q: 如何编译程序能让gprof工具使用?

A: 使用-p参数。不过根据bug列表,intel架构的mac系统不能正常运行gprof, 以后将在ubuntu下将这个例子写出来。


Q: 如果源代码的扩展名不是gcc默认支持的扩展名,那么编译会出现什么情况?

A: 将上面的hello.c复制一个为hello.xichen,使用gcc -o hello  hello.xichen编译:

gcc编译命令----小话c语言(14)

可以看到出现了问题;可以使用-x参数将文件当成指定类型的文件来编译:

gcc  -x  c  hello.xichen  -o  hello是将hello.xichen当成c代码编译:

gcc编译命令----小话c语言(14)

可以看出已经正确编译了; -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编译命令----小话c语言(14)

使用gcc  -o  hello  hello.c编译:

gcc编译命令----小话c语言(14)

可以看到,这样就没有问题。


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编译命令----小话c语言(14)

可以看到出现了编译错误;使用gcc  hello.c  -o  hello编译:

gcc编译命令----小话c语言(14)


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编译命令----小话c语言(14)

使用gcc  unsigned_signed_char.c  -o  unsigned_signed_char  -funsigned-char编译运行:

gcc编译命令----小话c语言(14)

使用 gcc  unsigned_signed_char.c  -o  unsigned_signed_char  -fsigned-char来编译运行:

gcc编译命令----小话c语言(14)


Q: 如果有的时候在一个文件中忘记包含了头文件,如何用编译参数插入头文件呢?

A: 可以使用-include参数。代码如下,保存为no_header.c:

int main()
{
    fprintf(stdout, "no header file\n");
    return 0;
}
使用gcc  no_header.c  -o  no_header编译:

gcc编译命令----小话c语言(14)

可以看到,编译出错了;改用gcc  no_header.c  -o  no_header  -include  /usr/include/stdio.h编译:

gcc编译命令----小话c语言(14)

运行ok:

gcc编译命令----小话c语言(14)

同样,可以使用-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编译:

gcc编译命令----小话c语言(14)

可以看到编译ok,且imacros.h中的add函数声明和imacros.c中的add函数声明不一致的问题也没有任何警告,因为-imacros仅仅将imacros.h文件中的宏进行处理,其它没有处理。

运行结果:

gcc编译命令----小话c语言(14)

修改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编译:

gcc编译命令----小话c语言(14)

可以看到,编译出错了,就是因为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.编译:

gcc编译命令----小话c语言(14)

可以看出,编译出了问题,因为-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都可以正确编译。

gcc编译命令----小话c语言(14)


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编译:

gcc编译命令----小话c语言(14)

可以看出,使用了-nostdinc参数,编译器将不在系统头文件路径下搜索, -I.将使得它在本目录下搜索,结果没找到stdlib.h头文件,报错了;可以去掉-nostdinc参数选项,使用gcc  nostdinc.c  -o  nostdinc  -I.编译即可:

gcc编译命令----小话c语言(14)

或者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编译命令----小话c语言(14)

使用gcc  warning.c  -o  warning  -Wall编译:

gcc编译命令----小话c语言(14)
可以看出,包括i没有被使用的警告也被显示出来;

使用gcc  warning.c  -o  warning  -w编译:

gcc编译命令----小话c语言(14)

可以看到没有任何警告信息显示了。


xichen

2012-5-19 22:26:32