找回密码
 注册
搜索
查看: 2142|回复: 15

[讨论] Linux 下 C 语言编程

[复制链接]
发表于 2005-12-5 21:11:00 | 显示全部楼层 |阅读模式
<P align=center><BIG><BIG><FONT color=#ff9900>Linux 下 C 语言编程</FONT> </BIG></BIG></P>
<P align=right><FONT color=#ff9900>原著:Rick McMullin</FONT></P>
<H3 align=center><FONT color=#ff9900>前言</FONT></H3>
<P>Linux的发行版中包含了很多软件开发工具. 它们中的很多是用于 C 和 C++应用程序开发的. 本文介绍了在 Linux 下能用于 C 应用程序开发和调试的工具. 本文的主旨是介绍如何在 Linux 下使用 C 编译器和其他 C 编程工具, 而非 C 语言编程的教程. 在本文中你将学到以下知识:
  
<UL>
<LI>什么是 C
<LI>GNU C 编译器
<LI>用 <TT>gdb </TT>来调试GCC应用程序 </LI></UL>
<CENTER></CENTER>    你也能看到随 Linux 发行的其他有用的 C 编程工具. 这些工具包括源程序美化程序(pretty print programs), 附加的调试工具, 函数原型自动生成工具(automatic function prototypers).
<CENTER>
<DL>
<DD>
<HR width="90%">
</CENTER><B>注意: </B>源程序美化程序(pretty print programs)自动帮你格式化源代码产生始终如一的缩进格式.  
<CENTER>
<HR width="90%">
</DD></DL>
<H3><FONT color=#ff9900>什么是 C?</FONT></H3>    C 是一种在 UNIX 操作系统的早期就被广泛使用的通用编程语言. 它最早是由贝尔实验室的 Dennis Ritchie 为了 UNIX 的辅助开发而写的, 开始时 UNIX 是用汇编语言和一种叫 B 的语言编写的. 从那时候起, C 就成为世界上使用最广泛计算机语言.
  
    C 能在编程领域里得到如此广泛支持的原因有以下一些:
<UL>
<LI>它是一种非常通用的语言. 几乎你所能想到的任何一种计算机上都有至少一种能用的 C 编译器. 并且它的语法和函数库在不同的平台上都是统一的, 这个特性对开发者来说很有吸引力.
<LI>用 C 写的程序执行速度很快.
<LI>C 是所有版本的UNIX上的系统语言. </LI></UL>    C 在过去的二十年中有了很大的发展. 在80年代末期美国国家标准协会(American National Standards Institute)发布了一个被称为 ANSI C 的 C 语言标准.这更加保证了将来在不同平台上的 C 的一致性. 在80年代还出现了一种 C 的面向对象的扩展称为 C++. C++ 将在另一篇文章 "C++ 编程"中描述.
<P>    Linux 上可用的 C 编译器是 GNU C 编译器, 它建立在自由软件基金会的编程许可证的基础上, 因此可以自由发布. 你能在 Linux 的发行光盘上找到它.
  
  
  
<H3><FONT color=#ff9900>GNU C 编译器</FONT></H3>    随 Slackware Linux 发行的 GNU C 编译器(GCC)是一个全功能的 ANSI C 兼容编译器. 如果你熟悉其他操作系统或硬件平台上的一种 C 编译器, 你将能很快地掌握 GCC. 本节将介绍如何使用 GCC 和一些 GCC 编译器最常用的选项.
  
<H4><FONT color=#ff9900>使用 GCC</FONT></H4>    通常后跟一些选项和文件名来使用 GCC 编译器. <TT>gcc </TT>命令的基本用法如下: <PRE><FONT color=#0066ff>gcc [options] [filenames]</FONT></PRE>    命令行选项指定的操作将在命令行上每个给出的文件上执行. 下一小节将叙述一些你会最常用到的选项.
  
<H4>GCC 选项</H4>    GCC 有超过100个的编译选项可用. 这些选项中的许多你可能永远都不会用到, 但一些主要的选项将会频繁用到. 很多的 GCC 选项包括一个以上的字符. 因此你必须为每个选项指定各自的连字符, 并且就象大多数 Linux 命令一样你不能在一个单独的连字符后跟一组选项. 例如, 下面的两个命令是不同的: <PRE><FONT color=#0066ff>gcc -p -g test.c

gcc -pg test.c</FONT></PRE>    第一条命令告诉 GCC 编译 <TT>test.c</TT> 时为 <TT>prof</TT> 命令建立剖析(profile)信息并且把调试信息加入到可执行的文件里. 第二条命令只告诉 GCC 为 <TT>gprof</TT> 命令建立剖析信息.
  
    当你不用任何选项编译一个程序时, GCC 将会建立(假定编译成功)一个名为 <TT>a.out</TT> 的可执行文件. 例如, 下面的命令将在当前目录下产生一个叫 <TT>a.out</TT> 的文件: <PRE><FONT color=#0066ff>gcc test.c</FONT></PRE>    你能用 <TT>-o</TT> 编译选项来为将产生的可执行文件指定一个文件名来代替 <TT>a.out. </TT>例如, 将一个叫 <TT>count.c </TT>的 C 程序编译为名叫 <TT>count</TT> 的可执行文件, 你将输入下面的命令: <PRE><FONT color=#0066ff>gcc -o count count.c</FONT></PRE>
<DL>
<DD>
<HR width="90%">
<B>注意:</B> 当你使用 <TT>-o</TT> 选项时, <TT>-o</TT> 后面必须跟一个文件名.  
<HR width="90%">
</DD></DL>    GCC 同样有指定编译器处理多少的编译选项. <TT>-c</TT> 选项告诉 GCC 仅把源代码编译为目标代码而跳过汇编和连接的步骤. 这个选项使用的非常频繁因为它使得编译多个 C 程序时速度更快并且更易于管理. 缺省时 GCC 建立的目标代码文件有一个 <TT>.o</TT> 的扩展名.
<P><TT>    -S</TT> 编译选项告诉 GCC 在为 C 代码产生了汇编语言文件后停止编译. GCC 产生的汇编语言文件的缺省扩展名是 <TT>.s .</TT> <TT>-E</TT> 选项指示编译<TT>器</TT>仅对输入文件进行预处理. 当这个选项被使用时, 预处理器的输出被送到标准输出而不是储存在文件里.
<H4><FONT color=#ff9900>优 化 选 项</FONT></H4>    当你用 GCC 编译 C 代码时, 它会试着用最少的时间完成编译并且使编译后的代码易于调试. 易于调试意味着编译后的代码与源代码有同样的执行次序, 编译后的代码没有经过优化. 有很多选项可用于告诉 GCC 在耗费更多编译时间和牺牲易调试性的基础上产生更小更快的可执行文件. 这些选项中最典型的是<TT>-O</TT> 和 <TT>-O2</TT> 选项.
<P>    <TT>-O</TT> 选项告诉 GCC 对源代码进行基本优化. 这些优化在大多数情况下都会使程序执行的更快. <TT>-O2</TT> 选项告诉 GCC 产生尽可能小和尽可能快的代码. <TT>-O2</TT> 选项将使编译的速度比使用 <TT>-O</TT> 时慢. 但通常产生的代码执行速度会更快.
<P>    除了 <TT>-O</TT> 和 <TT>-O2</TT> 优化选项外, 还有一些低级选项用于产生更快的代码. 这些选项非常的特殊, 而且最好只有当你完全理解这些选项将会对编译后的代码产生什么样的效果时再去使用. 这些选项的详细描述, 请参考 GCC 的指南页, 在命令行上键入 <TT>man gcc</TT> .
<H4><FONT color=#ff9900>调试和剖析选项</FONT></H4>    GCC 支持数种调试和剖析选项. 在这些选项里你会最常用到的是 <TT>-g</TT> 和 <TT>-pg </TT>选项.
    -g 选项告诉 GCC 产生能被 GNU 调试器使用的调试信息以便调试你的程序. GCC 提供了一个很多其他 C 编译器里没有的特性, 在 GCC 里你能使 -g 和 -O (产生优化代码)联用. 这一点非常有用因为你能在与最终产品尽可能相近的情况下调试你的代码. 在你同时使用这两个选项时你必须清楚你所写的某些代码已经在优化时被 GCC 作了改动. 关于调试 C 程序的更多信息请看下一节"用 gdb 调试 C 程序"  .
    -pg 选项告诉 GCC 在你的程序里加入额外的代码, 执行时, 产生 gprof 用的剖析信息以显示你的程序的耗时情况. 关于 gprof 的更多信息请参考 "gprof" 一节.
  
<H3><FONT color=#ff9900>用 gdb 调试 GCC 程序</FONT></H3>    Linux 包含了一个叫 gdb 的 GNU 调试程序. gdb 是一个用来调试 C 和 C++ 程序的强力调试器. 它使你能在程序运行时观察程序的内部结构和内存的使用情况. 以下是 gdb 所提供的一些功能:
<UL>
<LI>它使你能监视你程序中变量的值.
<LI>它使你能设置断点以使程序在指定的代码行上停止执行.
<LI>它使你能一行行的执行你的代码.
</LI></UL>    在命令行上键入 <TT>gdb </TT>并按回车键就可以运行 <TT>gdb </TT>了, 如果一切正常的话, <TT>gdb </TT>将被启动并且你将在屏幕上看到类似的内容: <PRE><FONT color=#0066ff>GDB is free software and you are welcome to distribute copies of it

under certain conditions; type "show copying" to see the conditions.

There is absolutely no warranty for GDB; type "show warranty" for details.

GDB 4.14 (i486-slakware-linux), Copyright 1995 Free Software Foundation, Inc.

(gdb)</FONT></PRE>    当你启动 <TT>gdb </TT>后, 你能在命令行上指定很多的选项. 你也可以以下面的方式来运行 <TT>gdb</TT> : <PRE><FONT color=#0066ff>gdb &lt;fname&gt;</FONT></PRE>    当你用这种方式运行 <TT>gdb</TT> , 你能直接指定想要调试的程序. 这将告诉<TT>gdb</TT> 装入名为 fname 的可执行文件. 你也可以用 <TT>gdb</TT> 去检查一个因程序异常终止而产生的 core 文件, 或者与一个正在运行的程序相连. 你可以参考 <TT>gdb </TT>指南页或在命令行上键入 <TT>gdb -h</TT> 得到一个有关这些选项的说明的简单列表.
  
<H4><FONT color=#ff9900>为调试编译代码(Compiling Code for Debugging)</FONT></H4>    为了使 <TT>gdb</TT> 正常工作, 你必须使你的程序在编译时包含调试信息. 调试信息包含你程序里的每个变量的类型和在可执行文件里的地址映射以及源代码的行号.  <TT>gdb</TT> 利用这些信息使源代码和机器码相关联.
<P>    在编译时用 -g 选项打开调试选项.
  
<H4><FONT color=#ff9900>gdb 基本命令</FONT></H4>     <TT>gdb</TT> 支持很多的命令使你能实现不同的功能. 这些命令从简单的文件装入到允许你检查所调用的堆栈内容的复杂命令, 表27.1列出了你在用 <TT>gdb</TT> 调试时会用到的一些命令. 想了解 <TT>gdb</TT> 的详细使用请参考 <TT>gdb</TT> 的指南页. </CENTER>
 楼主| 发表于 2005-12-5 21:12:00 | 显示全部楼层
<H4><FONT color=#ff9900>gdb 基本命令</FONT></H4>     <TT>gdb</TT> 支持很多的命令使你能实现不同的功能. 这些命令从简单的文件装入到允许你检查所调用的堆栈内容的复杂命令, 表27.1列出了你在用 <TT>gdb</TT> 调试时会用到的一些命令. 想了解 <TT>gdb</TT> 的详细使用请参考 <TT>gdb</TT> 的指南页.
<P> <FONT color=#ff9900> <B><FONT size=+1>表 27.1. 基本 gdb 命令.</FONT></B>  </FONT>
<TABLE border=1>

<TR align=left rowspan="1">
<TD align=left><I>命   令</I></TD>
<TD align=left><I>描  述</I></TD></TR>
<TR align=left rowspan="1">
<TD align=left><TT>file</TT></TD>
<TD align=left>装入想要调试的可执行文件.</TD></TR>
<TR align=left rowspan="1">
<TD align=left><TT>kill</TT></TD>
<TD align=left>终止正在调试的程序.</TD></TR>
<TR align=left rowspan="1">
<TD align=left><TT>list</TT></TD>
<TD align=left>列出产生执行文件的源代码的一部分.</TD></TR>
<TR align=left rowspan="1">
<TD align=left><TT>next</TT></TD>
<TD align=left>执行一行源代码但不进入函数内部.</TD></TR>
<TR align=left rowspan="1">
<TD align=left><TT>step</TT></TD>
<TD align=left>执行一行源代码而且进入函数内部.</TD></TR>
<TR align=left rowspan="1">
<TD align=left><TT>run</TT></TD>
<TD align=left>执行当前被调试的程序</TD></TR>
<TR align=left rowspan="1">
<TD align=left><TT>quit</TT></TD>
<TD align=left>终止 <TT>gdb</TT></TD></TR>
<TR align=left rowspan="1">
<TD align=left><TT>watch</TT></TD>
<TD align=left>使你能监视一个变量的值而不管它何时被改变.</TD></TR>
<TR align=left rowspan="1">
<TD align=left><TT>break</TT></TD>
<TD align=left>在代码里设置断点, 这将使程序执行到这里时被挂起.</TD></TR>
<TR align=left rowspan="1">
<TD align=left><TT>make</TT></TD>
<TD align=left>使你能不退出 <TT>gdb</TT> 就可以重新产生可执行文件.</TD></TR>
<TR align=left rowspan="1">
<TD align=left><TT>shell</TT></TD>
<TD align=left>使你能不离开 <TT>gdb</TT> 就执行 UNIX shell 命令. </TD></TR></TABLE>  
  
<P>     <TT>gdb</TT> 支持很多与 UNIX shell 程序一样的命令编辑特征. 你能象在 <TT>bash</TT> 或 <TT>tcsh</TT>里那样按 Tab<TT> </TT>键<TT>让</TT> <TT>gdb</TT> 帮你补齐一个唯一的命令, 如果不唯一的话 <TT>gdb</TT> 会列出所有匹配的命令. 你也能用光标键上下翻动历史命令.
<H4><FONT color=#ff9900>gdb 应用举例</FONT></H4>    本节用一个实例教你一步步的用 <TT>gdb</TT> 调试程序. 被调试的程序相当的简单, 但它展示了 <TT>gdb</TT> 的典型应用.
  
    下面列出了将被调试的程序. 这个程序被称为 <TT>greeting</TT> , 它显示一个简单的问候, 再用反序将它列出. <PRE><FONT color=#0066ff>#include  &lt;stdio.h&gt;



main ()

{

  char my_string[] = "hello there";



  my_print (my_string);

  my_print2 (my_string);

}



void my_print (char *string)

{

  printf ("The string is %s\n", string);

}



void my_print2 (char *string)

{

  char *string2;

  int size, i;



  size = strlen (string);

  string2 = (char *) malloc (size + 1);

  for (i = 0; i &lt; size; i++)

    string2[size - i] = string;

  string2[size+1] = `\0';

  printf ("The string printed backward is %s\n", string2);

}</FONT></PRE>    用下面的命令编译它:
  <PRE><FONT color=#0066ff>gcc -o test test.c</FONT></PRE>    这个程序执行时显示如下结果: <PRE><FONT color=#0066ff>The string is hello there

The string printed backward is</FONT></PRE>    输出的第一行是正确的, 但第二行打印出的东西并不是我们所期望的. 我们所设想的输出应该是: <PRE><FONT color=#0066ff>The string printed backward is ereht olleh</FONT></PRE>    由于某些原因, <TT>my_print2</TT> 函数没有正常工作. 让我们用  <TT>gdb</TT> 看看问题究竟出在哪儿, 先键入如下命令:
  <PRE><FONT color=#0066ff>gdb greeting</FONT></PRE>
<DL>
<DD>
<HR width="90%">
<B>注意:</B> 记得在编译 <TT>greeting</TT> 程序时把调试选项打开.  
<HR width="90%">
</DD></DL>    如果你在输入命令时忘了把要调试的程序作为参数传给 <TT>gdb</TT> , 你可以在 <TT>gdb</TT> 提示符下用 file 命令来载入它:
  <PRE><FONT color=#0066ff>(gdb) file greeting</FONT></PRE>    这个命令将载入 <TT>greeting</TT> 可执行文件就象你在 <TT>gdb</TT> 命令行里装入它一样.
<P>    这时你能用 <TT>gdb</TT> 的 run 命令来运行 <TT>greeting</TT> 了. 当它在 <TT>gdb</TT> 里被运行后结果大约会象这样: <PRE><FONT color=#0066ff>(gdb) run

Starting program: /root/greeting

The string is hello there

The string printed backward is

Program exited with code 041</FONT></PRE>    这个输出和在 <TT>gdb</TT> 外面运行的结果一样. 问题是, 为什么反序打印没有工作? 为了找出症结所在, 我们可以在 <TT>my_print2</TT> 函数的 <TT>for</TT> 语句后设一个断点, 具体的做法是在 <TT>gdb</TT> 提示符下键入 <TT>list</TT> 命令三次, 列出源代码: <PRE><FONT color=#0066ff>(gdb) list

(gdb) list

(gdb) list</FONT></PRE>
<DL>
<DD>
<HR width="90%">
<B>技巧:</B>  在 <TT>gdb</TT> 提示符下按回车健将重复上一个命令.  
<HR width="90%">
</DD></DL>    第一次键入 <TT>list</TT> 命令的输出如下:
  <PRE><FONT color=#0066ff>1       #include  &lt;stdio.h&gt;

2

3       main ()

4       {

5         char my_string[] = "hello there";

6

7         my_print (my_string);

8         my_print2 (my_string);

9       }

10</FONT></PRE>    如果按下回车, <TT>gdb</TT> 将再执行一次 <TT>list</TT> 命令, 给出下列输出:
  <PRE><FONT color=#0066ff>11      my_print (char *string)

12      {

13        printf ("The string is %s\n", string);

14      }

15

16      my_print2 (char *string)

17      {

18        char *string2;

19        int size, i;

20</FONT></PRE>    再按一次回车将列出 <TT>greeting</TT> 程序的剩余部分: <PRE><FONT color=#0066ff>21        size = strlen (string);

22        string2 = (char *) malloc (size + 1);

23        for (i = 0; i &lt; size; i++)

24          string2[size - i] = string;

25        string2[size+1] = `\0';

26        printf ("The string printed backward is %s\n", string2);

27      }</FONT></PRE>    根据列出的源程序, 你能看到要设断点的地方在第24行, 在 <TT>gdb</TT> 命令行提示符下键入如下命令设置断点: <PRE><FONT color=#0066ff>(gdb) break 24</FONT></PRE><TT>    gdb</TT> 将作出如下的响应: <PRE><FONT color=#0066ff>Breakpoint 1 at 0x139: file greeting.c, line 24

(gdb)</FONT></PRE>  
    现在再键入 <TT>run </TT>命令, 将产生如下的输出:
  <PRE><FONT color=#0066ff>Starting program: /root/greeting

The string is hello there



Breakpoint 1, my_print2 (string = 0xbfffdc4 "hello there") at greeting.c :24

24  string2[size-i]=string</FONT></PRE>    你能通过设置一个观察 <TT>string2[size - i]</TT> 变量的值的观察点来看出错误是怎样产生的, 做法是键入:
  <PRE><FONT color=#0066ff>(gdb) watch string2[size - i]</FONT></PRE><TT>    gdb</TT> 将作出如下回应: <PRE><FONT color=#0066ff>Watchpoint 2: string2[size - i]</FONT></PRE>    现在可以用 <TT>next</TT> 命令来一步步的执行 <TT>for</TT> 循环了:
  <PRE><FONT color=#0066ff>(gdb) next</FONT></PRE>    经过第一次循环后,  <TT>gdb</TT> 告诉我们 <TT>string2[size - i]</TT> 的值是 <TT>`h`.</TT> <TT>gdb</TT> 用如下的显示来告诉你这个信息:
  <PRE><FONT color=#0066ff>Watchpoint 2, string2[size - i]

Old value = 0 `\000'

New value = 104 `h'

my_print2(string = 0xbfffdc4 "hello there") at greeting.c:23

23 for (i=0; i&lt;size; i++)</FONT></PRE>    这个值正是期望的. 后来的数次循环的结果都是正确的. 当 <TT>i=10 </TT>时, 表达式 <TT>string2[size - i]</TT> 的值等于 <TT>`e`</TT>,  <TT>size - i</TT> 的值等于 1, 最后一个字符已经拷到新串里了.
<P>    如果你再把循环执行下去, 你会看到已经没有值分配给 <TT>string2[0] </TT>了,<TT> </TT> 而它是新串的第一个字符, 因为 <TT>malloc</TT> 函数在分配内存时把它们初始化为空(null)字符. 所以 <TT>string2</TT> 的第一个字符是空字符. 这解释了为什么在打印 <TT>string2</TT> 时没有任何输出了.
<P>    现在找出了问题出在哪里, 修正这个错误是很容易的. 你得把代码里写入 <TT>string2</TT> 的第一个字符的的偏移量改为 <TT>size - 1</TT> 而不是 <TT>size</TT>. 这是因为 <TT>string2</TT> 的大小为 12, 但起始偏移量是 0, 串内的字符从偏移量 0 到 偏移量 10, 偏移量 11 为空字符保留. </P>
点评回复

使用道具 举报

 楼主| 发表于 2005-12-5 21:13:00 | 显示全部楼层
为了使代码正常工作有很多种修改办法. 一种是另设一个比串的实际大小小 1 的变量. 这是这种解决办法的代码: <PRE><FONT color=#0066ff>#include  &lt;stdio.h&gt;



main ()


{

  char my_string[] = "hello there";



  my_print (my_string);

  my_print2 (my_string);

}



my_print (char *string)

{

  printf ("The string is %s\n", string);

}



my_print2 (char *string)

{

  char *string2;

  int size, size2, i;



  size = strlen (string);

  size2 = size -1;

  string2 = (char *) malloc (size + 1);

  for (i = 0; i &lt; size; i++)

    string2[size2 - i] = string;

  string2[size] = `\0';

  printf ("The string printed backward is %s\n", string2);

}</FONT></PRE>
<H3><FONT color=#ff9900>另外的 C 编程工具</FONT></H3>    Slackware Linux 的发行版中还包括一些我们尚未提到的 C 开发工具. 本节将介绍这些工具和它们的典型用法.
<H4>xxgdb</H4><TT>    xxgdb</TT> 是 <TT>gdb</TT> 的一个基于 X Window 系统的图形界面.  <TT>xxgdb </TT>包括了命令行版的 <TT>gdb</TT> 上的所有特性.  <TT>xxgdb </TT>使你能通过按按钮来执行常用的命令. 设置了断点的地方也用图形来显示.
  
    你能在一个 <TT>Xterm</TT> 窗口里键入下面的命令来运行它: <PRE><FONT color=#0066ff>xxgdb</FONT></PRE>    你能用 <TT>gdb</TT> 里任何有效的命令行选项来初始化 <TT>xxgdb</TT> . 此外 <TT>xxgdb</TT> 也有一些特有的命令行选项, 表 27.2 列出了这些选项.
  <B><FONT size=+1>表 27.2.  xxgdb 命令行选项.</FONT></B>     
<TABLE border=1>

<TR align=left rowspan="1">
<TD align=left width=70><I>选  项</I></TD>
<TD align=left><I>描  述</I></TD></TR>
<TR align=left rowspan="1">
<TD align=left width=70><TT>db_name</TT></TD>
<TD align=left>指定所用调试器的名字, 缺省是 <TT>gdb</TT>.</TD></TR>
<TR align=left rowspan="1">
<TD align=left width=70><TT>db_prompt</TT></TD>
<TD align=left>指定调试器提示符, 缺省为 <TT>gdb</TT>.</TD></TR>
<TR align=left rowspan="1">
<TD align=left width=70><TT>gdbinit</TT></TD>
<TD align=left>指定初始化 <TT>gdb</TT> 的命令文件的文件名, 缺省为 <TT>.gdbinit</TT>.  </TD></TR>
<TR align=left rowspan="1">
<TD align=left width=70><TT>nx</TT></TD>
<TD align=left>告诉 <TT>xxgdb</TT> 不执行 <TT>.gdbinit</TT> 文件.</TD></TR>
<TR align=left rowspan="1">
<TD align=left width=70><TT>bigicon</TT></TD>
<TD align=left>使用大图标.</TD></TR></TABLE>  
  
  
<H4>calls</H4><TT>     </TT>你可以在 <TT>sunsite.unc.edu</TT> FTP 站点用下面的路径:
<P><TT><FONT color=#3366ff>/pub/Linux/devel/lang/c/calls.tar.Z</FONT></TT>
<P>    来取得 <TT>calls , </TT>一些旧版本的 Linux CD-ROM 发行版里也附带有. 因为它是一个有用的工具, 我们在这里也介绍一下. 如果你觉得有用的话, 从 BBS, FTP, 或另一张CD-ROM 上弄一个拷贝.  <TT>calls</TT> 调用 GCC 的预处理器来处理给出的源程序文件, 然后输出这些文件的里的函数调用树图.
  
<DL>
<DD>
<HR width="90%">
<B>注意:</B> 在你的系统上安装 <TT>calls</TT> , 以超级用户身份登录后执行下面的步骤: 1. 解压和 <TT>untar</TT> 文件. 2. <TT>cd</TT> 进入 <TT>calls</TT> untar 后建立的子目录. 3. 把名叫 <TT>calls</TT> 的文件移动到 <TT>/usr/bin</TT> 目录. 4. 把名叫 <TT>calls.1</TT> 的文件移动到目录 <TT>/usr/man/man1</TT> . 5. 删除 <TT>/tmp/calls</TT> 目录. 这些步骤将把 <TT>calls</TT> 程序和它的指南页安装载你的系统上.  
<HR width="90%">
</DD></DL>    当 <TT>calls</TT> 打印出调用跟踪结果时, 它在函数后面用中括号给出了函数所在文件的文件名: <PRE><FONT color=#0066ff>main [test.c]</FONT></PRE>    如果函数并不是向 <TT>calls</TT> 给出的文件里的,  <TT>calls </TT>不知道所调用的函数来自哪里, 则只显示函数的名字: <PRE><FONT color=#0066ff>printf</FONT></PRE><TT>    calls</TT> 不对递归和静态函数输出. 递归函数显示成下面的样子: <PRE><FONT color=#0066ff>fact &lt;&lt;&lt; recursive in factorial.c &gt;&gt;&gt;</FONT></PRE>    静态函数象这样显示: <PRE><FONT color=#0066ff>total [static in calculate.c]</FONT></PRE>    作为一个例子, 假设用 <TT>calls</TT> 处理下面的程序:
  <PRE><FONT color=#0066ff>#include &lt;stdio.h&gt;



main ()

{

char my_string[] = "hello there";

my_print (my_string);

my_print2(my_string);

}



my_print (char *string)

{

printf ("The string is %s\n", string);

}



my_print2 (char *string)

{

  char *string2;

  int size, size2, i;



  size = strlen (string);

  size2 = size -1;

  string2 = (char *) malloc (size + 1);

  for (i = 0; i &lt; size; i++)

    string2[size2 - i] = string;

  string2[size] = `\0';

  printf ("The string printed backward is %s\n", string2);

}</FONT></PRE>    将产生如下的输出: <PRE><FONT color=#0066ff>    1 main [test.c]

    2       my_print [test.c]

    3             printf

    4       my_print2 [test.c]

    5             strlen

    6             malloc

    7             printf</FONT></PRE><TT>calls</TT> 有很多命令行选项来设置不同的输出格式, 有关这些选项的更多信息请参考 <TT>calls</TT> 的指南页. 方法是在命令行上键入 <TT>calls -h</TT> .
  
  
<H4><FONT color=#ff9900>cproto</FONT></H4><TT>    cproto</TT> 读入 C 源程序文件并自动为每个函数产生原型申明. 用 <TT>cproto</TT> 可以在写程序时为你节省大量用来定义函数原型的时间.
    如果你让 <TT>cproto</TT> 处理下面的代码: <PRE><FONT color=#0066ff>#include  &lt;stdio.h&gt;



main ()

{

  char my_string[] = "hello there";

  my_print (my_string);

  my_print2(my_string);

}



my_print (char *string)

{

  printf ("The string is %s\n", *string);

}



my_print2 (char *string)

{

  char *string2;

  int size, size2, i;



  size = strlen (string);

  size2 = size -1;

  string2 = (char *) malloc (size + 1);

  for (i = 0; i &lt; size; i++)

    string2[size2 - i] = string;

  string2[size] = `\0';

  printf ("The string printed backward is %s\n", string2);

}</FONT></PRE>    你将得到下面的输出: <PRE><FONT color=#0066ff>/* test.c */

int main(void);

int my_print(char *string);

int my_print2(char *string);</FONT></PRE>    这个输出可以重定向到一个定义函数原型的包含文件里.
<H4><FONT color=#ff9900>indent</FONT></H4><TT>    indent</TT> 实用程序是 Linux 里包含的另一个编程实用工具. 这个工具简单的说就为你的代码产生美观的缩进的格式. <TT>indent</TT> 也有很多选项来指定如何格式化你的源代码.这些选项的更多信息请看<TT>indent</TT> 的指南页, 在命令行上键入 <TT>indent -h</TT> .
  
<P>    下面的例子是 <TT>indent </TT>的缺省输出:
<P>    运行 <TT>indent </TT>以前的 C 代码: <PRE><FONT color=#0066ff>#include  &lt;stdio.h&gt;



main () {

      char my_string[] = "hello there";

  my_print (my_string);

     my_print2(my_string); }



my_print (char *string)

{

  printf    ("The string is %s\n", *string);

}



my_print2           (char *string) {

    char *string2;

      int size, size2, i;



      size = strlen (string);

      size2 = size -1;

      string2 = (char *) malloc (size + 1);

  for (i = 0; i &lt; size; i++)

            string2[size2 - i] = string;

      string2[size] = `\0';


      printf ("The string printed backward is %s\n", string2);

}</FONT></PRE>    运行 <TT>indent </TT>后的 C 代码: <PRE><FONT color=#0066ff>#include  &lt;stdio.h&gt;



main ()

{

  char my_string[] = "hello there";

  my_print (my_string);

  my_print2 (my_string);

}



my_print (char *string)

{

  printf ("The string is %s\n", *string);

}



my_print2 (char *string)

{

  char *string2;

  int size, size2, i;



  size = strlen (string);

  size2 = size -1;

  string2 = (char *) malloc (size + 1);

  for (i = 0; i &lt; size; i++)

    string2[size2 - i] = string;

  string2[size] = `\0';

  printf ("The string printed backward is %s\n", string2);

}</FONT></PRE><TT>    </TT> <TT>indent </TT>并不改变代码的实质内容, 而只是改变代码的外观. 使它变得更可读, 这永远是一件好事.
<H4>gprof</H4><TT>    gprof</TT> 是安装在你的 Linux 系统的 <TT>/usr/bin</TT> 目录下的一个程序. 它使你能剖析你的程序从而知道程序的哪一个部分在执行时最费时间.
<P><TT>    gprof</TT> 将告诉你程序里每个函数被调用的次数和每个函数执行时所占时间的百分比. 你如果想提高你的程序性能的话这些信息非常有用.
<P>    为了在你的程序上使用 gprof, 你必须在编译程序时加上 -pg 选项. 这将使程序在每次执行时产生一个叫 gmon.out 的文件. gprof 用这个文件产生剖析信息.
<P>    在你运行了你的程序并产生了 gmon.out 文件后你能用下面的命令获得剖析信息: <PRE><FONT color=#0066ff>gprof &lt;program_name&gt;</FONT></PRE>    参数 program_name 是产生 gmon.out 文件的程序的名字.
<DL>
<DD>
<HR width="90%">
<B>技巧:</B> gprof 产生的剖析数据很大, 如果你想检查这些数据的话最好把输出重定向到一个文件里.  
<HR width="90%">
</DD></DL>
<H4>f2c 和 p2c</H4><TT>    f2c</TT> 和 <TT>p2c </TT>是两个源代码转换程序. f2c 把 FORTRAN 代码转换为 C 代码, p2c 把 Pascal 代码转换为 C 代码. 当你安装 GCC 时这两个程序都会被安装上去.
<P>    如果你有一些用 FORTRAN 或 Pascal 写的代码要用 C 重写的话, f2c 和 p2c 对你非常有用. 这两个程序产生的 C 代码一般不用修改就直接能被 GCC 编译.
<P>    如果要转换的 FORTRAN 或 Pascal 程序比较小的话可以直接使用 f2c 或 p2c 不用加任何选项. 如果要转换的程序比较庞大, 包含很多文件的话你可能要用到一些命令行选项.
<P>    在一个 FORTRAN 程序上使用 f2c , 输入下面的命令: <PRE><FONT color=#0066ff>f2c my_fortranprog.f</FONT></PRE>
<DL>
<DD>
<HR>
<B>注意:</B> <TT>f2c</TT> 要求被转换的程序的扩展名为 <TT>.f</TT> 或 a <TT>.F</TT> .  
<HR>
</DD></DL>    要把一个Pascal 程序装换为 C 程序, 输入下面的命令: <PRE><FONT color=#0066ff>p2c my_pascalprogram.pas</FONT></PRE>    这两个程序产生的 C 源代码的文件名都和原来的文件名相同, 但扩展名由 .f 或 .pas 变为 .c.
点评回复

使用道具 举报

发表于 2006-4-14 17:25:00 | 显示全部楼层
<P>好东西,受益匪浅!!谢谢楼主。有没有更详细点的关于gcc和gdb的文档?要是有的话辛苦您给我发一份:<a href="mailtxinfatan@hotmail.com" target="_blank" >xinfatan@hotmail.com</A></P><P>最近刚开始学习linux。</P>
点评回复

使用道具 举报

发表于 2006-5-8 15:03:00 | 显示全部楼层
3x
点评回复

使用道具 举报

发表于 2006-5-10 14:33:00 | 显示全部楼层
到哪去找搂住这样的好人呢?多谢
点评回复

使用道具 举报

发表于 2006-7-28 10:19:00 | 显示全部楼层
能把以上资料发一份到我邮箱里吗? 这里复制实在复杂了些。[em07]

感激不尽哦![em03]     leond2000@163.com
点评回复

使用道具 举报

发表于 2006-8-3 22:06:00 | 显示全部楼层
不错不错[em05]
点评回复

使用道具 举报

发表于 2006-8-28 08:36:00 | 显示全部楼层
不错,不错,好动西
点评回复

使用道具 举报

发表于 2006-8-28 19:23:00 | 显示全部楼层
顶一个。
点评回复

使用道具 举报

发表于 2006-9-11 17:54:00 | 显示全部楼层
这个用来扫盲好.
点评回复

使用道具 举报

发表于 2006-10-19 17:42:00 | 显示全部楼层
对呀,可不可以给我也发一份呢。谢谢了。sailor904@163.com
点评回复

使用道具 举报

发表于 2006-10-27 13:59:00 | 显示全部楼层

难得

难得
[em05]
点评回复

使用道具 举报

发表于 2006-10-28 11:17:00 | 显示全部楼层
这年头象楼主这么慷慨的太少了啊[em04]
点评回复

使用道具 举报

发表于 2006-11-5 22:38:00 | 显示全部楼层
顶!!!!!!!!!!!!!!!!!!!!!
点评回复

使用道具 举报

发表于 2007-1-6 15:57:00 | 显示全部楼层
楼主好人一个!
点评回复

使用道具 举报

高级模式
B Color Image Link Quote Code Smilies

本版积分规则

Archiver|手机版|小黑屋|52RD我爱研发网 ( 沪ICP备2022007804号-2 )

GMT+8, 2024-11-27 04:02 , Processed in 0.054892 second(s), 18 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表