博文

gcc 简介(2007-05-07 19:35:00)

摘要:gcc 简介
 
    本节学习GNU推出的Linux系统下C编译器----gcc,主要介绍这种编译器的基本原理和使用方法,以及编译过程中所产生的错误的原因及对策。 gcc简介
Linux系统下的gcc(GNU C Compiler)是GNU推出的功能强大、性能优越的多平台编译器,是GNU的代表作品之一。gcc是可以在多种硬体平台上编译出可执行程序的超级编译器,其执行效率与一般的编译器相比平均效率要高20%~30%。 gcc编译器能将C、C++语言源程序、汇程式化序和目标程序编译、连接成可执行文件,如果没有给出可执行文件的名字,gcc将生成一个名为a.out的文件。在Linux系统中,可执行文件没有统一的后缀,系统从文件的属性来区分可执行文件和不可执行文件。而gcc则通过后缀来区别输入文件的类别,下面我们来介绍gcc所遵循的部分约定规则。 .c为后缀的文件,C语言源代码文件; .a为后缀的文件,是由目标文件构成的档案库文件; .C,.cc或.cxx 为后缀的文件,是C++源代码文件; .h为后缀的文件,是程序所包含的头文件; .i 为后缀的文件,是已经预处理过的C源代码文件; .ii为后缀的文件,是已经预处理过的C++源代码文件; .m为后缀的文件,是Objective-C源代码文件; .o为后缀的文件,是编译后的目标文件; .s为后缀的文件,是汇编语言源代码文件; .S为后缀的文件,是经过预编译的汇编语言源代码文件。 gcc的执行过程
虽然我们称gcc是C语言的编译器,但使用gcc由C语言源代码文件生成可执行文件的过程不仅仅是编译的过程,而是要经历四个相互关联的步骤∶预处理(也称预编译,Preprocessing)、编译(Compilation)、汇编(Assembly)和连接(Linking)。 命令gcc首先调用cpp进行预处理,在预处理过程中,对源代码文件中的文件包含(include)、预编译语句(如宏定义define等)进行分析。接着调用cc1进行编译,这个阶段根据输入文件生成以.o为后缀的目标文件。汇编过程是针对汇编语言的步骤,调用as进行工作,一般来讲,.S为后缀的汇编语言源代码文件和汇编、.s为后缀的汇编语言文件经过预编译和汇......

阅读全文(3591) | 评论:0

C语言之C语言的底层操作(2007-05-07 17:13:00)

摘要:C语言之C语言的底层操作
 作者:未知 来源:不详 编辑:
 
  概述   C语言的内存模型基本上对应了现在von Neumann(冯·诺伊曼)计算机的实际存储模型,很好的达到了对机器的映射,这是C/C++适合做底层开发的主要原因,另外,C语言适合做底层开发还有另外一个原因,那就是C语言对底层操作做了很多的的支持,提供了很多比较底层的功能。   下面结合问题分别进行阐述。   问题:移位操作   在运用移位操作符时,有两个问题必须要清楚:   (1)、在右移操作中,腾空位是填 0 还是符号位;   (2)、什么数可以作移位的位数。   答案与分析:   ">>"和"<<"是指将变量中的每一位向右或向左移动, 其通常形式为:   右移: 变量名>>移位的位数   左移: 变量名<<移位的位数   经过移位后, 一端的位被"挤掉",而另一端空出的位以0 填补,在C语言中的移位不是循环移动的。   (1) 第一个问题的答案很简单,但要根据不同的情况而定。如果被移位的是无符号数,则填 0 。如果是有符号数,那么可能填 0 或符号位。如果你想解决右移操作中腾空位的填充问题,就把变量声明为无符号型,这样腾空位会被置 0。   (2) 第二个问题的答案也很简单:如果移动 n 位,那么移位的位数要不小于 0 ,并且一定要小于 n 。这样就不会在一次操作中把所有数据都移走。   比如,如果整型数据占 32 位,n 是一整型数据,则 n << 31 和 n << 0 都合法,而 n << 32 和 n << -1 都不合法。   注意即使腾空位填符号位,有符号整数的右移也不相当与除以 。为了证明这一点,我们可以想一下 -1 >> 1 不可能为 0 。
 
  问题:位段结构   struct RPR_ATD_TLV_HEADER
  {
  ULONG res1:6;
  ULONG type:10;
  ULONG res1:6;
  ULONG length:10;
  };   位段结构是一种特殊的结构, ......

阅读全文(2032) | 评论:0

gcc 常用命令行列表(2007-05-04 18:08:00)

摘要:gcc 常用命令行列表 -o FILE 指定输出文件名,在编译为目标代码时,这一选项不是必须的。如果FILE没有指定,缺省文件名是a.out. -c 只编译不链接 -DFOO=BAR 在命令行定义预处理宏FOO,其值为BAR -IDIRNAME 将DIRNAME加入到头文件的搜索目录列表中 -LDIRNAME 将DIRNAME加入到库文件的搜索目录列表中,缺省情况下gcc 只链接共享库 -static 链接静态库,即执行静态链接 -lFOO 链接名为libFOO的函数库 -g 在可执行程序中包含标准调试信息 -ggdb 在可执行程序中包含只有GNU debugger才能使别的达两条是信息 -O 优化编译过的代码 -ON 指定代码优化的级别为N,o......

阅读全文(1958) | 评论:0

C语言初学者入门讲座 第十六讲 文件(2)(2007-05-04 17:25:00)

摘要:C语言初学者入门讲座 第十六讲 文件(2)   字符串读写函数fgets和fputs   一、读字符串函数fgets函数的功能是从指定的文件中读一个字符串到字符数组中,函数调用的形式为: fgets(字符数组名,n,文件指针);其中的n是一个正整数。表示从文件中读出的字符串不超过 n-1个字符。在读入的最后一个字符后加上串结束标志'/0'。例如:fgets(str,n,fp);的意义是从fp所指的文件中读出n-1个字符送入字符数组str中。   [例10.4]从e10_1.c文件中读入一个含10个字符的字符串。 #include main() { FILE *fp; char str[11]; if((fp=fopen("e10_1.c","rt"))==NULL) { printf("Cannot open file strike any key exit!"); getch(); exit(1); } fgets(str,11,fp); printf("%s",str); fclose(fp); }   本例定义了一个字符数组str共11个字节,在以读文本文件方式打开文件e101.c后,从中读出10个字符送入str数组,在数组最后一个单元内将加上'/0',然后在屏幕上显示输出str数组。输出的十个字符正是例10.1程序的前十个字符。   对fgets函数有两点说明:   1. 在读出n-1个字符之前,如遇到了换行符或EOF,则读出结束。   2. fgets函数也有返回值,其返回值是字符数组的首地址。   二、写字符串函数fputs   fputs函数的功能是向指定的文件写入一个字符串,其调用形式为: fputs(字符串,文件指针) 其中字符串可以是字符串常量,也可以是字符数组名, 或指针 变量,例如: fputs(“abcd“,fp);   其意义是把字符串“abcd”写入fp所指的文件之中。[例10.5]在例10.2中建立的文件string中追加一个字符串。 #include main() { FILE *fp; char ch,st[20]; if((fp=fopen("string","at+"))==NULL) { printf("Can......

阅读全文(2335) | 评论:0

C语言初学者入门讲座 第十六讲 文件(1)(2007-05-04 17:24:00)

摘要:C语言初学者入门讲座 第十六讲 文件(1)   所谓“文件”是指一组相关数据的有序集合。 这个数据集有一个名称,叫做文件名。实际上在前面的各章中我们已经多次使用了文件,例如源程序文件、目标文件、可执行文件、库文件 (头文件)等。文件通常是驻留在外部介质(如磁盘等)上的,在使用时才调入内存中来。从不同的角度可对文件作不同的分类。从用户的角度看,文件可分为普通文件和设备文件两种。   普通文件是指驻留在磁盘或其它外部介质上的一个有序数据集,可以是源文件、目标文件、可执行程序; 也可以是一组待输入处理的原始数据,或者是一组输出的结果。对于源文件、目标文件、 可执行程序可以称作程序文件,对输入输出数据可称作数据文件。   设备文件是指与主机相联的各种外部设备,如显示器、打印机、键盘等。在操作系统中,把外部设备也看作是一个文件来进行管理,把它们的输入、输出等同于对磁盘文件的读和写。 通常把显示器定义为标准输出文件,一般情况下在屏幕上显示有关信息就是向标准输出文件输出。如前面经常使用的printf,putchar 函数就是这类输出。键盘通常被指定标准的输入文件, 从键盘上输入就意味着从标准输入文件上输入数据。scanf,getchar函数就属于这类输入。   从文件编码的方式来看,文件可分为ASCII码文件和二进制码文件两种。   ASCII文件也称为文本文件,这种文件在磁盘中存放时每个字符对应一个字节,用于存放对应的ASCII码。例如,数5678的存储形式为: ASC码:  00110101 00110110 00110111 00111000      ↓     ↓    ↓    ↓ 十进制码: 5     6    7    8 共占用4个字节。ASCII码文件可在屏幕上按字符显示, 例如源程序文件就是ASCII文件,用DOS命令TYPE可显示文件的内容。 由于是按字符显示,因此能读懂文件内容。   二进制文件是按二进制的编码方式来存放文件的。 例如, 数5678的存储形式为: 00010110 00101110只占二个字节。二进制文件虽然也可在屏幕上显示,但其内容无法读懂。C系统在处理这些文件时,并不区分类型,都看成是字符流,按字节进行处理。输入输出字符流的开始和结束只由程序控制而不受物理符号(如回车符)的控制。 因此也把这种文......

阅读全文(2237) | 评论:0

C语言初学者入门讲座 第十五讲 预处理(2007-05-04 17:22:00)

摘要:C语言初学者入门讲座 第十五讲 预处理   概述   在前面各章中,已多次使用过以“#”号开头的预处理命令。如包含命令# include,宏定义命令# define等。在源程序中这些命令都放在函数之外, 而且一般都放在源文件的前面,它们称为预处理部分。   所谓预处理是指在进行编译的第一遍扫描(词法扫描和语法分析)之前所作的工作。预处理是C语言的一个重要功能, 它由预处理程序负责完成。当对一个源文件进行编译时, 系统将自动引用预处理程序对源程序中的预处理部分作处理, 处理完毕自动进入对源程序的编译。   C语言提供了多种预处理功能,如宏定义、文件包含、 条件编译等。合理地使用预处理功能编写的程序便于阅读、修改、 移植和调试,也有利于模块化程序设计。本章介绍常用的几种预处理功能。   宏定义   在C语言源程序中允许用一个标识符来表示一个字符串, 称为“宏”。被定义为“宏”的标识符称为“宏名”。在编译预处理时,对程序中所有出现的“宏名”,都用宏定义中的字符串去代换, 这称为“宏代换”或“宏展开”。   宏定义是由源程序中的宏定义命令完成的。 宏代换是由预处理程序自动完成的。在C语言中,“宏”分为有参数和无参数两种。 下面分别讨论这两种“宏”的定义和调用。   无参宏定义   无参宏的宏名后不带参数。其定义的一般形式为: #define 标识符 字符串其中的“#”表示这是一条预处理命令。凡是以“#”开头的均为预处理命令。“define”为宏定义命令。 “标识符”为所定义的宏名。“字符串”可以是常数、表达式、格式串等。在前面介绍过的符号常量的定义就是一种无参宏定义。此外,常对程序中反复使用的表达式进行宏定义。例如: # define M (y*y+3*y) 定义M表达式(y*y+3*y)。在编写源程序时,所有的(y*y+3*y)都可由M代替,而对源程序作编译时,将先由预处理程序进行宏代换,即用 (y*y+3*y)表达式去置换所有的宏名M,然后再进行编译。 #define M (y*y+3*y) main(){  int s,y;  printf("input a number: ");  scanf("%d",&y);  s=3*M+4*M+5*M;  printf("s=%d/n",s); } ......

阅读全文(1783) | 评论:0

C语言初学者入门讲座 第十四讲 枚举与位运算(2)(2007-05-04 17:21:00)

摘要:C语言初学者入门讲座 第十四讲 枚举与位运算(2)   位域   有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态,用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域, 并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。一、位域的定义和位域变量的说明位域定义与结构定义相仿,其形式为:   struct 位域结构名   { 位域列表 };   其中位域列表的形式为: 类型说明符 位域名:位域长度   例如: struct bs {  int a:8;  int b:2;  int c:6; };   位域变量的说明与结构变量说明的方式相同。 可采用先定义后说明,同时定义说明或者直接说明这三种方式。例如: struct bs {  int a:8;  int b:2;  int c:6; }data;   说明data为bs变量,共占两个字节。其中位域a占8位,位域b占2位,位域c占6位。对于位域的定义尚有以下几点说明:   1. 一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。例如: struct bs {  unsigned a:4  unsigned :0 /*空域*/  unsigned b:4 /*从下一单元开始存放*/  unsigned c:4 }   在这个位域定义中,a占第一字节的4位,后4位填0表示不使用,b从第二字节开始,占用4位,c占用4位。   2. 由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进位。   3. 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。例如: struct k {  int a:1  int :2 /*该2位不能使用*/  int b:3  int c:2 };   ......

阅读全文(2114) | 评论:0

C语言初学者入门讲座 第十四讲 枚举与位运算(1)(2007-05-04 17:21:00)

摘要:C语言初学者入门讲座 第十四讲 枚举与位运算(1)   在实际问题中,有些变量的取值被限定在一个有限的范围内。例如,一个星期内只有七天,一年只有十二个月, 一个班每周有六门课程等等。如果把这些量说明为整型,字符型或其它类型显然是不妥当的。 为此,C语言提供了一种称为“枚举”的类型。在“枚举”类型的定义中列举出所有可能的取值,被说明为该“枚举”类型的变量取值不能超过定义的范围。应该说明的是, 枚举类型是一种基本数据类型,而不是一种构造类型,因为它不能再分解为任何基本类型。   枚举类型的定义和枚举变量的说明   一、枚举的定义   枚举类型定义的一般形式为: enum 枚举名 {  枚举值表 };   在枚举值表中应罗列出所有可用值。这些值也称为枚举元素。   例如: enum weekday {  sun,mou,tue,wed,thu,fri,sat };   该枚举名为weekday,枚举值共有7个,即一周中的七天。 凡被说明为weekday类型变量的取值只能是七天中的某一天。   二、枚举变量的说明   如同结构和联合一样,枚举变量也可用不同的方式说明, 即先定义后说明,同时定义说明或直接说明。设有变量a,b,c被说明为上述的weekday,可采用下述任一种方式: enum weekday { ...... }; enum weekday a,b,c;或者为: enum weekday { ...... }a,b,c;或者为: enum { ...... }a,b,c;   枚举类型变量的赋值和使用   枚举类型在使用中有以下规定:   1. 枚举值是常量,不是变量。不能在程序中用赋值语句再对它赋值。例如对枚举weekday的元素再作以下赋值: sun=5;mon=2;sun=mon; 都是错误的。   2. 枚举元素本身由系统定义了一个表示序号的数值,从0 开始顺序定义为0,1,2…。如在weekday中,sun值为0,mon值为1, …,sat值为6。 main(){  enum weekday  {   sun,mon,tue,wed,thu,fri,sat  } a,b,c;  a=sun;  b=mon;  ......

阅读全文(2433) | 评论:0

C语言初学者入门讲座 第十三讲 联合(2007-05-04 17:19:00)

摘要:C语言初学者入门讲座 第十三讲 联合   “联合”与“结构”有一些相似之处。但两者有本质上的不同。在结构中各成员有各自的内存空间,一个结构变量的总长度是各成员长度之和。而在“联合”中,各成员共享一段内存空间, 一个联合变量的长度等于各成员中最长的长度。应该说明的是,这里所谓的共享不是指把多个成员同时装入一个联合变量内, 而是指该联合变量可被赋予任一成员值,但每次只能赋一种值,赋入新值则冲去旧值。如前面介绍的“单位”变量,如定义为一个可装入“班级”或“教研室”的联合后,就允许赋予整型值(班级)或字符串(教研室)。要么赋予整型值,要么赋予字符串,不能把两者同时赋予它。联合类型的定义和联合变量的说明一个联合类型必须经过定义之后, 才能把变量说明为该联合类型。   一、联合的定义   定义一个联合类型的一般形式为: union 联合名 {  成员表 };   成员表中含有若干成员,成员的一般形式为: 类型说明符 成员名 成员名的命名应符合标识符的规定。   例如: union perdata {  int class;  char office[10]; };   定义了一个名为perdata的联合类型,它含有两个成员,一个为整型,成员名为class;另一个为字符数组,数组名为office。联合定义之后,即可进行联合变量说明,被说明为perdata类型的变量,可以存放整型量class或存放字符数组office。   二、联合变量的说明   联合变量的说明和结构变量的说明方式相同, 也有三种形式。即先定义,再说明;定义同时说明和直接说明。以perdata类型为例,说明如下: union perdata {  int class;  char officae[10]; }; union perdata a,b; /*说明a,b为perdata类型*/   或者可同时说明为: union perdata {  int class;  char office[10]; }  a,b;或直接说明为: union {  int class;  char office[10]; } a,b   经说明后的a,b变量均为perdata类型。 它们的内存分......

阅读全文(2051) | 评论:0

C语言初学者入门讲座 第十二讲 结构(3)(2007-05-04 17:18:00)

摘要:C语言初学者入门讲座 第十二讲 结构(3)   结构指针变量作函数参数   在ANSI C标准中允许用结构变量作函数参数进行整体传送。 但是这种传送要将全部成员逐个传送,特别是成员为数组时将会使传送的时间和空间开销很大,严重地降低了程序的效率。 因此最好的办法就是使用指针,即用指针变量作函数参数进行传送。这时由实参传向形参的只是地址,从而减少了时间和空间的开销。   [例7.8]题目与例7.4相同,计算一组学生的平均成绩和不及格人数。   用结构指针变量作函数参数编程。 struct stu {  int num;  char *name;  char sex;  float score;}boy[5]={   {101,"Li ping",'M',45},   {102,"Zhang ping",'M',62.5},   {103,"He fang",'F',92.5},   {104,"Cheng ling",'F',87},   {105,"Wang ming",'M',58},  }; main() {  struct stu *ps;  void ave(struct stu *ps);  ps=boy;  ave(ps); } void ave(struct stu *ps) {  int c=0,i;  float ave,s=0;  for(i=0;iscore;   if(ps->scorenum=102;  ps->name="Zhang ping";  ps->sex='M';  ps->score=62.5;  printf("Number=%d/nName=%s/n",ps->num,ps->name);  printf("Sex=%c/nScore=%f/n",ps->sex,ps->score);  free(ps); }   本例中,定义了结构stu,定义了stu类型指针变量ps。然后分配一块stu大内存区,并把首地址赋予ps,使ps指向该区域。再以ps为指向结构的指针变量对各成员赋值,并用printf 输出各成员值。最后用free函数释放ps指向的内存空间。 整个程序包含了申请内存空间、使用内存空间、释放内存空间三个步骤,实现存储空间的动态......

阅读全文(2161) | 评论:0