﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>IT博客-roguishangel</title><link>http://www.cnitblog.com/roguishangel/</link><description /><language>zh-cn</language><lastBuildDate>Tue, 05 May 2026 03:12:34 GMT</lastBuildDate><pubDate>Tue, 05 May 2026 03:12:34 GMT</pubDate><ttl>60</ttl><item><title>深刻理解Linux进程间通信（IPC）</title><link>http://www.cnitblog.com/roguishangel/archive/2005/12/30/5926.html</link><dc:creator>牙刷</dc:creator><author>牙刷</author><pubDate>Fri, 30 Dec 2005 15:25:00 GMT</pubDate><guid>http://www.cnitblog.com/roguishangel/archive/2005/12/30/5926.html</guid><wfw:comment>http://www.cnitblog.com/roguishangel/comments/5926.html</wfw:comment><comments>http://www.cnitblog.com/roguishangel/archive/2005/12/30/5926.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/roguishangel/comments/commentRss/5926.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/roguishangel/services/trackbacks/5926.html</trackback:ping><description><![CDATA[简介<br>
http://www-128.ibm.com/developerworks/cn/linux/l-ipc/<br>
<br>
管道及命名管道<br>
http://www-128.ibm.com/developerworks/cn/linux/l-ipc/part1/<br>
<br>
<span style="font-weight: bold;">信号(上)<br>
http://www-128.ibm.com/developerworks/cn/linux/l-ipc/part2/index1.html<br>
<br>
</span><span style="font-weight: bold;">信号(下)<br>
http://www-128.ibm.com/developerworks/cn/linux/l-ipc/part2/index2.html<br>
<br>
消息队列<br>
http://www-128.ibm.com/developerworks/cn/linux/l-ipc/part3/<br>
<br>
信号量<br>
http://www-128.ibm.com/developerworks/cn/linux/l-ipc/part4/<br>
<br>
共享内存(上)<br>
http://www-128.ibm.com/developerworks/cn/linux/l-ipc/part5/index1.html<br>
<br>
</span><span style="font-weight: bold;">共享内存(下)<br>
http://www-128.ibm.com/developerworks/cn/linux/l-ipc/part5/index2.html<br>
<br>
socket<br>
http://www-128.ibm.com/developerworks/cn/linux/l-ipc/part6/<br>
</span><img src ="http://www.cnitblog.com/roguishangel/aggbug/5926.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/roguishangel/" target="_blank">牙刷</a> 2005-12-30 23:25 <a href="http://www.cnitblog.com/roguishangel/archive/2005/12/30/5926.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>库的使用与生成</title><link>http://www.cnitblog.com/roguishangel/archive/2005/11/20/4750.html</link><dc:creator>牙刷</dc:creator><author>牙刷</author><pubDate>Sun, 20 Nov 2005 11:27:00 GMT</pubDate><guid>http://www.cnitblog.com/roguishangel/archive/2005/11/20/4750.html</guid><wfw:comment>http://www.cnitblog.com/roguishangel/comments/4750.html</wfw:comment><comments>http://www.cnitblog.com/roguishangel/archive/2005/11/20/4750.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/roguishangel/comments/commentRss/4750.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/roguishangel/services/trackbacks/4750.html</trackback:ping><description><![CDATA[<span class="postbody">
基本概念
<br>

<br>
    库有动态与静态两种，动态通常用.so为后缀，静态用.a为后缀。例如：libhello.so libhello.a
<br>

<br>
为了在同一系统中使用不同版本的库，可以在库文件名后加上版本号为后缀,例如： libhello.so.1.0,由于程序连接默认以.so为文件后缀名。所以为了使用这些库，通常使用建立符号连接的方式。
<br>
   ln -s libhello.so.1.0 libhello.so.1
<br>
   ln -s libhello.so.1 libhello.so
<br>

<br>
使用库
<br>
   
<br>
当要使用静态的程序库时，连接器会找出程序所需的函数，然后将它们拷贝到执行文件，由于这种拷贝是完整的，所以一旦连接成功，静态程序库也就不再需要了。
然而，对动态库而言，就不是这样。动态库会在执行程序内留下一个标记‘指明当程序执行时，首先必须载入这个库。由于动态库节省空间，linux下进行连接
的缺省操作是首先连接动态库，也就是说，如果同时存在静态和动态库，不特别指定的话，将与动态库相连接。
<br>
   现在假设有一个叫hello的程序开发包，它提供一个静态库libhello.a 一个动态库libhello.so,一个头文件hello.h,头文件中提供sayhello()这个函数
<br>
/* hello.h */
<br>
 void sayhello();
<br>
另外还有一些说明文档。这一个典型的程序开发包结构
<br>
 1.与动态库连接
<br>
    linux默认的就是与动态库连接，下面这段程序testlib.c使用hello库中的sayhello()函数
<br>

<br>
/*testlib.c*/
<br>
#include &lt;hello.h&gt;
<br>
#include &lt;stdio.h&gt;
<br>

<br>
int main()
<br>
{
<br>
sayhello();
<br>
return 0;
<br>
}
<br>

<br>
使用如下命令进行编译
<br>
$gcc -c testlib.c -o testlib.o
<br>
用如下命令连接：
<br>
$gcc testlib.o -lhello -o testlib
<br>
在连接时要注意，假设libhello.o 和libhello.a都在缺省的库搜索路径下/usr/lib下，如果在其它位置要加上-L参数
<br>
   与与静态库连接麻烦一些，主要是参数问题。还是上面的例子：
<br>
$gcc testlib.o -o testlib -WI,-Bstatic -lhello
<br>
   注：这个特别的"-WI，-Bstatic"参数，实际上是传给了连接器ld.
<br>
指示它与静态库连接，如果系统中只有静态库当然就不需要这个参数了。
<br>
  如果要和多个库相连接，而每个库的连接方式不一样，比如上面的程序既要和libhello进行静态连接，又要和libbye进行动态连接，其命令应为：
<br>
$gcc testlib.o -o testlib -WI,-Bstatic -lhello -WI,-Bdynamic -lbye
<br>
  3.动态库的路径问题
<br>
    为了让执行程序顺利找到动态库，有三种方法：
<br>
(1)把库拷贝到/usr/lib和/lib目录下。
<br>
(2)在LD_LIBRARY_PATH环境变量中加上库所在路径。例如动态库libhello.so在/home/ting/lib目录下，以bash为例，使用命令：
<br>
$export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/ting/lib
<br>
(3) 修改/etc/ld.so.conf文件，把库所在的路径加到文件末尾，并执行ldconfig刷新。这样，加入的目录下的所有库文件都可见、
<br>

<br>
4.查看库中的符号
<br>
有时候可能需要查看一个库中到底有哪些函数，nm命令可以打印出库中的涉及到的所有符号。库既可以是静态的也可以是动态的。nm列出的符号有很多，常见的
有三种，一种是在库中被调用，但并没有在库中定义(表明需要其他库支持)，用U表示；一种是库中定义的函数，用T表示，这是最常见的；另外一种是所谓的
“弱态”符号，它们虽然在库中被定义，但是可能被其他库中的同名符号覆盖，用W表示。例如，假设开发者希望知道上央提到的hello库中是否定义了
printf():
<br>
$nm libhello.so |grep printf
<br>
      U printf
<br>
U表示符号printf被引用，但是并没有在函数内定义，由此可以推断，要正常使用hello库，必须有其它库支持，再使用ldd命令查看hello依赖于哪些库：
<br>
$ldd hello
<br>
   libc.so.6=&gt;/lib/libc.so.6(0x400la000)
<br>
   /lib/ld-linux.so.2=&gt;/lib/ld-linux.so.2 (0x40000000)
<br>
从上面的结果可以继续查看printf最终在哪里被定义，有兴趣可以go on
<br>

<br>

<br>
生成库
<br>

<br>
   第一步要把源代码编绎成目标代码。以下面的代码为例，生成上面用到的hello库：
<br>
/* hello.c */
<br>
#include &lt;stdio.h&gt;
<br>
void sayhello()
<br>
{
<br>
printf("hello,world\n");
<br>
}
<br>
用gcc编绎该文件，在编绎时可以使用任何全法的编绎参数，例如-g加入调试代码等：
<br>
gcc -c hello.c -o hello.o
<br>

<br>
1.连接成静态库
<br>
  连接成静态库使用ar命令，其实ar是archive的意思
<br>
$ar cqs libhello.a hello.o
<br>
2.连接成动态库
<br>
   生成动态库用gcc来完成，由于可能存在多个版本，因此通常指定版本号：
<br>
$gcc -shared -Wl,-soname,libhello.so.1 -o libhello.so.1.0 hello.o
<br>
  另外再建立两个符号连接：
<br>
$ln -s libhello.so.1.0 libhello.so.1
<br>
$ln -s libhello.so.1 libhello.so
<br>
这样一个libhello的动态连接库就生成了。最重要的是传gcc -shared 参数使其生成是动态库而不是普通执行程序。
<br> -Wl
表示后面的参数也就是-soname,libhello.so.1直接传给连接器ld进行处理。实际上，每一个库都有一个soname，当连接器发现它正
在查找的程序库中有这样一个名称，连接器便会将soname嵌入连结中的二进制文件内，而不是它正在运行的实际文件名，在程序执行期间，程序会查找拥有
soname名字的文件，而不是库的文件名，换句话说，soname是库的区分标志。
<br>
  这样做的目的主要是允许系统中多个版本的库文件共存，习惯上在命名库文件的时候通常与soname相同
<br>
   libxxxx.so.major.minor
<br>
其中，xxxx是库的名字，major是主版本号，minor 是次版本号</span><img src ="http://www.cnitblog.com/roguishangel/aggbug/4750.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/roguishangel/" target="_blank">牙刷</a> 2005-11-20 19:27 <a href="http://www.cnitblog.com/roguishangel/archive/2005/11/20/4750.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用diff/patch为代码打补丁</title><link>http://www.cnitblog.com/roguishangel/archive/2005/11/20/4748.html</link><dc:creator>牙刷</dc:creator><author>牙刷</author><pubDate>Sun, 20 Nov 2005 11:00:00 GMT</pubDate><guid>http://www.cnitblog.com/roguishangel/archive/2005/11/20/4748.html</guid><wfw:comment>http://www.cnitblog.com/roguishangel/comments/4748.html</wfw:comment><comments>http://www.cnitblog.com/roguishangel/archive/2005/11/20/4748.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/roguishangel/comments/commentRss/4748.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/roguishangel/services/trackbacks/4748.html</trackback:ping><description><![CDATA[<span class="postbody">
1.diff的使用
<br>
   diff可以完成比较功能，生成补丁文件
<br>
格式：：diff [option] oldfile newfile
<br>
常用的option选项有：
<br>
-r 对目录进行递归处理
<br>
-u 输出统一格式，diff有"传统"和"统一"两种格式，现在一般使用"统一"格式，比较而言，统一格式生成的文件大，但包含了更多的信息，有利于阅读与定位
<br>
-N 补丁中包含整个新文件
<br>
-a 补丁中包含二进制文件
<br>
  缺省时,diff向标准输出打印，所以一般都重定向到文件并以patch为后缀，也就是所谓的补丁文件
<br>
举例：
<br>
 /*  oldfile hello.c */
<br>
void main()
<br>
{
<br>
printf("hello the world!\n");
<br>
}
<br>

<br>
/* newfile hello-new.c */
<br>
void main()
<br>
{
<br>
printf("HELLO THE WORLD!\n");
<br>
}
<br>

<br>
使用以下命令生成补丁文件hello.patch
<br>
$diff -u hello.c hello-new.c &gt;hello.patch
<br>

<br>

diff可以对整个目录进行比较，生成补丁文件
<br>
例如有hello-1.0 和hello-1.1两个目录，其中hello-1.1为hello-1.0的更新
<br>
命令：
<br>
$diff -ruNa hello-1.0 hello-1.1 &gt;hello-1.1.patch
<br>

<br>

<br>
2.patch的使用
<br>
把补丁运用到原代码上的命令为patch
<br>
patch [-b] suffix &lt;patchfile
<br>

<br>
如果patch失败，patch会把成功的行打上补丁，失败的行存为以.rej为后缀的文件折，并生成原文件的备份，如果成功则不生成备份。 -b选项可以指定后缀名。
<br>
   注意：运行patch所在的目录应该与用diff生成补丁的时候一致。例如，上面在hello-1.0目录的上层目录生成补丁文件，patch时也应该在此目录进行。</span><img src ="http://www.cnitblog.com/roguishangel/aggbug/4748.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/roguishangel/" target="_blank">牙刷</a> 2005-11-20 19:00 <a href="http://www.cnitblog.com/roguishangel/archive/2005/11/20/4748.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>c与c++程序连接问题</title><link>http://www.cnitblog.com/roguishangel/archive/2005/11/20/4747.html</link><dc:creator>牙刷</dc:creator><author>牙刷</author><pubDate>Sun, 20 Nov 2005 10:50:00 GMT</pubDate><guid>http://www.cnitblog.com/roguishangel/archive/2005/11/20/4747.html</guid><wfw:comment>http://www.cnitblog.com/roguishangel/comments/4747.html</wfw:comment><comments>http://www.cnitblog.com/roguishangel/archive/2005/11/20/4747.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/roguishangel/comments/commentRss/4747.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/roguishangel/services/trackbacks/4747.html</trackback:ping><description><![CDATA[<span class="postbody">
  它们之间的连接问题主要是因为c c++编绎器对函数名译码的方式不能所引起的，考虑下面两个函数
<br>
/* c*/
<br>
int strlen(char* string)
<br>
{
<br>
...
<br>
}
<br>

<br>
//c++
<br>
int strlen(char* string)
<br>
{
<br>
...
<br>
}
<br>
 
<br>
两个函数完全一样。在c在函数是通过函数名来识别的，而在C++中，由于存在函数的重载问题，函数的识别方式通函数名，函数的返回类型，函数参数列表三者
组合来完成的。因此上面两个相同的函数，经过C，C++编绎后会产生完全不同的名字。所以，如果把一个用c编绎器编绎的目标代码和一个用C++编绎器编绎
的目标代码进行连接，就会出现连接失败的错误。
<br>

<br>
解决的方法是使用extern C，避免C++编绎器按照C++的方式去编绎C函数
<br>
在头文件中定义：
<br>
extern "C" int strlen(char* string)
<br>
或
<br>
extern "C"
<br>
{
<br>
int strlen(char* string)
<br>
}
<br>
当C++编绎器遇到extern "C"的时候就用传统的C函数编译方法对该函数进行编译。由于C编绎器不认识extern "C"这个编绎指令，而程序员又希望C，C++程序能共用这个头文件，因此通常在头文件中使用_cplusplus宏进行区分：
<br>
#if define _cplusplus
<br>
extern "C"{
<br>
#endif
<br>
int strlen(char* string)
<br>
#ifdefine _cplusplus
<br>
}
<br>
#endif</span><img src ="http://www.cnitblog.com/roguishangel/aggbug/4747.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/roguishangel/" target="_blank">牙刷</a> 2005-11-20 18:50 <a href="http://www.cnitblog.com/roguishangel/archive/2005/11/20/4747.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux守护进程</title><link>http://www.cnitblog.com/roguishangel/archive/2005/11/20/4745.html</link><dc:creator>牙刷</dc:creator><author>牙刷</author><pubDate>Sun, 20 Nov 2005 10:19:00 GMT</pubDate><guid>http://www.cnitblog.com/roguishangel/archive/2005/11/20/4745.html</guid><wfw:comment>http://www.cnitblog.com/roguishangel/comments/4745.html</wfw:comment><comments>http://www.cnitblog.com/roguishangel/archive/2005/11/20/4745.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/roguishangel/comments/commentRss/4745.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/roguishangel/services/trackbacks/4745.html</trackback:ping><description><![CDATA[守护进程最重要的特性是后台运行。在这一点上DOS下的常驻内存程序TSR与之相似。其次，守护进程必须与其运行前的环境隔离开来。这些环境包括未关闭的
文件描述符，控制终端，会话和进程组，工作目录以及文件创建掩模等。这些环境通常是守护进程从执行它的父进程（特别是shell）中继承下来的。最后，守
护进程的启动方式有其特殊之处。它可以在Linux系统启动时从启动脚本/etc/rc.d中启动，可以由作业规划进程crond启动，还可以由用户终端
（通常是shell）执行。<br>
<br>

1. 在后台运行。<br>

<br>

为避免挂起控制终端将Daemon放入后台执行。方法是在进程中调用fork使父进程终止，让Daemon在子进程中后台执行。<br>

<br>

if(pid=fork())<br>

<br>

exit(0);//是父进程，结束父进程，子进程继续<br>

<br>

2. 脱离控制终端，登录会话和进程组<br>

<br>

有必要先介绍一下Linux中的进程与控制终端，登录会话和进程组之间的关系：进程属于一个进程组，进程组号（GID）就是进程组长的进程号（PID）。登录会话可以包含多个进程组。这些进程组共享一个控制终端。这个控制终端通常是创建进程的登录终端。<br>

<br>

控制终端，登录会话和进程组通常是从父进程继承下来的。我们的目的就是要摆脱它们，使之不受它们的影响。方法是在第1点的基础上，调用setsid()使进程成为会话组长：<br>

setsid();<br>

<br>

说明：当进程是会话组长时setsid()调用失败。但第一点已经保证进程不是会话组长。setsid()调用成功后，进程成为新的会话组长和新的进程组长，并与原来的登录会话和进程组脱离。由于会话过程对控制终端的独占性，进程同时与控制终端脱离。<br>

<br>

3. 禁止进程重新打开控制终端<br>

<br>

现在，进程已经成为无终端的会话组长。但它可以重新申请打开一个控制终端。可以通过使进程不再成为会话组长来禁止进程重新打开控制终端：<br>

<br>

if(pid=fork())<br>

<br>

exit(0);//结束第一子进程，第二子进程继续（第二子进程不再是会话组长）<br>

<br>

4. 关闭打开的文件描述符<br>

<br>

进程从创建它的父进程那里继承了打开的文件描述符。如不关闭，将会浪费系统资源，造成进程所在的文件系统无法卸下以及引起无法预料的错误。按如下方法关闭它们：<br>

<br>

for(i=0;i 关闭打开的文件描述符close(i);&gt;<br>

<br>

5. 改变当前工作目录<br>

<br>

进程活动时，其工作目录所在的文件系统不能卸下。一般需要将工作目录改变到根目录。对于需要转储核心，写运行日志的进程将工作目录改变到特定目录如/tmpchdir("/")<br>

<br>

6. 重设文件创建掩模<br>

<br>

进程从创建它的父进程那里继承了文件创建掩模。它可能修改守护进程所创建的文件的存取位。为防止这一点，将文件创建掩模清除：umask(0);<br>

<br>

7. 处理SIGCHLD信号<br>

<br>

处理SIGCHLD信号并不是必须的。但对于某些进程，特别是服务器进程往往在请求到来时生成子进程处理请求。如果父进程不等待子进程结束，子进程将成为
僵尸进程（zombie）从而占用系统资源。如果父进程等待子进程结束，将增加父进程的负担，影响服务器进程的并发性能。在Linux下可以简单地将
SIGCHLD信号的操作设为SIG_IGN。<br>

<br>

signal(SIGCHLD,SIG_IGN);<br>

<br>

这样，内核在子进程结束时不会产生僵尸进程。这一点与BSD4不同，BSD4下必须显式等待子进程结束才能释放僵尸进程。<br>
<img src ="http://www.cnitblog.com/roguishangel/aggbug/4745.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/roguishangel/" target="_blank">牙刷</a> 2005-11-20 18:19 <a href="http://www.cnitblog.com/roguishangel/archive/2005/11/20/4745.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Gentoo里一个rpm2targz的脚本</title><link>http://www.cnitblog.com/roguishangel/archive/2005/11/20/4743.html</link><dc:creator>牙刷</dc:creator><author>牙刷</author><pubDate>Sun, 20 Nov 2005 09:36:00 GMT</pubDate><guid>http://www.cnitblog.com/roguishangel/archive/2005/11/20/4743.html</guid><wfw:comment>http://www.cnitblog.com/roguishangel/comments/4743.html</wfw:comment><comments>http://www.cnitblog.com/roguishangel/archive/2005/11/20/4743.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/roguishangel/comments/commentRss/4743.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/roguishangel/services/trackbacks/4743.html</trackback:ping><description><![CDATA[#!/bin/sh<br>
# Copyright 1997, 1998 Patrick Volkerding, Moorhead, Minnesota USA<br>
# All rights reserved.<br>
#<br>
# Redistribution and use of this script, with or without modification, is<br>
# permitted provided that the following conditions are met:<br>
#<br>
# 1. Redistributions of this script must retain the above copyright<br>
#&nbsp;&nbsp;&nbsp; notice, this list of conditions and the following disclaimer.<br>
#<br>
#&nbsp; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED<br>
#&nbsp; WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF<br>
#&nbsp; MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.&nbsp; IN NO<br>
#&nbsp; EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,<br>
#&nbsp; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,<br>
#&nbsp; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;<br>
#&nbsp; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,<br>
#&nbsp; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR<br>
#&nbsp; OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF<br>
#&nbsp; ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.<br>
#<br>
<br>
if [ "$TMPDIR" = "" ]; then<br>
&nbsp; TMPDIR=/tmp<br>
fi<br>
if [ "$1" = "" ]; then<br>
&nbsp; echo "$0:&nbsp; Converts RPM format to standard GNU tar + GNU zip format."<br>
&nbsp; echo
"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
(view converted packages with \"less\", install and remove"<br>
&nbsp; echo
"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
with \"installpkg\", \"removepkg\", \"pkgtool\", or manually"<br>
&nbsp; echo "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; with \"tar\")"<br>
&nbsp; echo<br>
&nbsp; echo "Usage:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $0 &lt;file.rpm&gt;"<br>
&nbsp; if [ "`basename $0`" = "rpm2tgz" ]; then<br>
&nbsp;&nbsp;&nbsp; echo "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (Outputs \"file.tgz\")"<br>
&nbsp; else<br>
&nbsp;&nbsp;&nbsp; echo "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (Outputs \"file.tar.gz\")"<br>
&nbsp; fi<br>
&nbsp; exit 1;<br>
fi<br>
for i in $* ; do<br>
&nbsp; if [ ! "$1" = "$*" ]; then<br>
&nbsp;&nbsp;&nbsp; echo "Processing file: $i"<br>
&nbsp; fi<br>
&nbsp; rm -rf $TMPDIR/rpm2targz$$ # clear the way, just in case of mischief<br>
&nbsp; mkdir $TMPDIR/rpm2targz$$<br>
&nbsp; ofn=`basename $i .rpm`.cpio<br>
&nbsp; dd ibs=`rpmoffset &lt; $i` skip=1 if=$i 2&gt; /dev/null | gzip -dc &gt; $TMPDIR/rpm2targz$$/$ofn<br>
&nbsp; ( cd $TMPDIR/rpm2targz$$<br>
&nbsp;&nbsp;&nbsp; cpio --extract --preserve-modification-time --make-directories &lt; $ofn 1&gt; /dev/null 2&gt; /dev/null<br>
&nbsp;&nbsp;&nbsp; rm -f $ofn<br>
&nbsp;&nbsp;&nbsp; find . -type d -perm 700 -exec chmod 755 {} \;<br>
&nbsp;&nbsp;&nbsp; tar cf - . ) &gt; `basename $i .rpm`.tar<br>
&nbsp;&nbsp;&nbsp; gzip -9 `basename $i .rpm`.tar<br>
&nbsp;&nbsp;&nbsp; if [ "`basename $0`" = "rpm2tgz" ]; then<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mv `basename $i .rpm`.tar.gz `basename $i .rpm`.tgz<br>
&nbsp;&nbsp;&nbsp; fi<br>
&nbsp; ( cd $TMPDIR ; rm -rf rpm2targz$$ )<br>
done<img src ="http://www.cnitblog.com/roguishangel/aggbug/4743.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/roguishangel/" target="_blank">牙刷</a> 2005-11-20 17:36 <a href="http://www.cnitblog.com/roguishangel/archive/2005/11/20/4743.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C语言中的可变参数</title><link>http://www.cnitblog.com/roguishangel/archive/2005/11/20/4738.html</link><dc:creator>牙刷</dc:creator><author>牙刷</author><pubDate>Sun, 20 Nov 2005 09:27:00 GMT</pubDate><guid>http://www.cnitblog.com/roguishangel/archive/2005/11/20/4738.html</guid><wfw:comment>http://www.cnitblog.com/roguishangel/comments/4738.html</wfw:comment><comments>http://www.cnitblog.com/roguishangel/archive/2005/11/20/4738.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/roguishangel/comments/commentRss/4738.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/roguishangel/services/trackbacks/4738.html</trackback:ping><description><![CDATA[一、什么是可变参数<br>
我们在C语言编程中有时会遇到一些参数个数可变的函数,例如printf()函数,其函数原型为:<br>
int printf( const char* format, ...);<br>
它除了有一个参数format固定以外,后面跟的参数的个数和类型是可变的（用三个点“…”做参数占位符）,实际调用时可以有以下的形式: printf("%d",i);<br>
printf("%s",s);<br>
printf("the number is %d ,string is:%s", i, s);&nbsp; &nbsp;<br>
以上这些东西已为大家所熟悉。但是究竟如何写可变参数的C函数以及这些可变参数的函数编译器是如何实现，这个问题却一直困扰了我好久。本文希望能对大家有些帮助.<br>
long sum(int i,...)<br>
{<br>
&nbsp; int *p,j;<br>
&nbsp; long s = 0;<br>
&nbsp; p = &amp;i+1;<br>
&nbsp; for (j=0;j&lt;i;j++)<br>
&nbsp;&nbsp;&nbsp; s += p[j];<br>
&nbsp;&nbsp; return s;<br>
}<br>
long Sum = sum(3,1,2,3);<br>
printf("%ld",Sum);<br>
Sum == 6<br>
<br>
二、写一个简单的可变参数的C函数<br>
先看例子程序。该函数至少有一个整数参数,其后占位符…，表示后面参数的个数不定. 在这个例子里，所有的输入参数必须都是整数，函数的功能只是打印所有参数的值.<br>
函数代码如下：<br>
//示例代码1：可变参数函数的使用<br>
#include "stdio.h"<br>
#include "stdarg.h"<br>
void simple_va_fun(int start, ...)<br>
{<br>
&nbsp;&nbsp;&nbsp; va_list arg_ptr;<br>
&nbsp;&nbsp;&nbsp; int nArgValue =start;<br>
&nbsp;&nbsp;&nbsp; int nArgCout=0;&nbsp;&nbsp;&nbsp;&nbsp; //可变参数的数目<br>
&nbsp;&nbsp;&nbsp; va_start(arg_ptr,start); //以固定参数的地址为起点确定变参的内存起始地址。<br>
&nbsp;&nbsp;&nbsp; do<br>
&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ++nArgCout;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("the %d th arg: %d",nArgCout,nArgValue);&nbsp;&nbsp;&nbsp;&nbsp; //输出各参数的值<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nArgValue =
va_arg(arg_ptr,int);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
//得到下一个可变参数的值<br>
&nbsp;&nbsp;&nbsp; } while(nArgValue !=
-1);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;<br>
&nbsp;&nbsp;&nbsp; return;<br>
}<br>
int main(int argc, char* argv[])<br>
{<br>
&nbsp;&nbsp;&nbsp; simple_va_fun(100,-1);<br>
&nbsp;&nbsp;&nbsp; simple_va_fun(100,200,-1);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>
}<br>
下面解释一下这些代码<br>
从这个函数的实现可以看到,我们使用可变参数应该有以下步骤:<br>
⑴由于在程序中将用到以下这些宏:<br>
void va_start( va_list arg_ptr, prev_param );<br>
type va_arg( va_list arg_ptr, type );<br>
void va_end( va_list arg_ptr );<br>
va在这里是variable-argument(可变参数)的意思.<br>
这些宏定义在stdarg.h中,所以用到可变参数的程序应该包含这个头文件.<br>
⑵函数里首先定义一个va_list型的变量,这里是arg_ptr,这个变<br>
量是存储参数地址的指针.因为得到参数的地址之后，再结合参数的类型，才能得到参数的值。<br>
⑶然后用va_start宏初始化⑵中定义的变量arg_ptr,这个宏的第二个参数是可变参数列表的前一个参数,即最后一个固定参数.<br>
⑷然后依次用va_arg宏使arg_ptr返回可变参数的地址,得到这个地址之后，结合参数的类型，就可以得到参数的值。<br>
⑸设定结束条件，这里的条件就是判断参数值是否为-1。注意被调的函数在调用时是不知道可变参数的正确数目的，程序员必须自己在代码中指明结束条件。至于为什么它不会知道参数的数目，读者在看完这几个宏的内部实现机制后，自然就会明白。<br>
<br>
<br>
<br>
(二)可变参数在编译器中的处理<br>
我们知道va_start,va_arg,va_end是在stdarg.h中被定义成宏的,&nbsp; 由于1)硬件平台的不同
2)编译器的不同,所以定义的宏也有所不同,下面看一下VC++6.0中stdarg.h里的代码（文件的路径为VC安装目录下的\vc98\
include\stdarg.h）<br>
typedef char *&nbsp; va_list;<br>
#define _INTSIZEOF(n) ((sizeof(n) + sizeof(int) - 1) &amp; ~(sizeof(int) - 1) )<br>
#define va_start(ap,v)&nbsp; ( ap = (va_list)&amp;v + _INTSIZEOF(v) )<br>
#define va_arg(ap,t)&nbsp;&nbsp;&nbsp; ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )<br>
#define va_end(ap)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ( ap = (va_list)0 )<br>
下面我们解释这些代码的含义：<br>
1、首先把va_list被定义成char*，这是因为在我们目前所用的PC机上，字符指针类型可以用来存储内存单元地址。而在有的机器上va_list是被定义成void*的<br>
2、定义_INTSIZEOF(n)主要是为了某些需要内存的对齐的系统.这个宏的目的是为了得到最后一个固定参数的实际内存大?gt;&gt;Ｔ谖业幕魃现苯佑胹izeof运朔创妫猿绦虻脑诵薪峁挂裁挥杏跋臁＃ê笪慕吹轿易约旱氖迪郑?<br>
3、 va_start的定义为 &amp;v+_INTSIZEOF(v)
,这里&amp;v是最后一个固定参数的起始地址，再加上其实际占用大小后，就得到了第一个可变参数的起始内存地址。所以我们运行va_start
(ap, v)以后,ap指向第一个可变参数在的内存地址,有了这个地址，以后的事情就简单了。<br>
这里要知道两个事情：<br>
&nbsp;&nbsp;&nbsp; ⑴在intel+windows的机器上，函数栈的方向是向下的，栈顶指针的内存地址低于栈底指针，所以先进栈的数据是存放在内存的高地址处。<br>
&nbsp;&nbsp;&nbsp; (2)在VC等绝大多数C编译器中，默认情况下，参数进栈的顺序是由右向左的，因此，参数进栈以后的内存模型如下图所示：最后一个固定参数的地址位于第一个可变参数之下，并且是连续存储的。<br>
|——————————————————————————|<br>
|&nbsp; 最后一个可变参数&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp; -&gt;高内存地址处<br>
|——————————————————————————|<br>
&nbsp;&nbsp; ...................<br>
|——————————————————————————|<br>
|&nbsp;
第N个可变参数&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;
-&gt;va_arg(arg_ptr,int)后arg_ptr所指的地方,<br>
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp; 即第N个可变参数的地址。<br>
|——————————————— |&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; ………………………….<br>
|——————————————————————————|<br>
|&nbsp;
第一个可变参数&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;
-&gt;va_start(arg_ptr,start)后arg_ptr所指的地方<br>
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp; 即第一个可变参数的地址<br>
|——————————————— |&nbsp;&nbsp;&nbsp; &nbsp;<br>
|———————————————————————— ——|<br>
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|<br>
|&nbsp; 最后一个固定参数&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp; -&gt; start的起始地址<br>
|—————————————— —|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .................<br>
|—————————————————————————— |<br>
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
| &nbsp;<br>
|——————————————— |&nbsp; -&gt; 低内存地址处<br>
<br>
(4) va_arg():有了va_start的良好基础，我们取得了第一个可变参数的地址，在va_arg()里的任务就是根据指定的参数类型取得本参数的值，并且把指针调到弦桓霾问钠鹗嫉刂贰?<br>
因此，现在再来看va_arg()的实现就应该心中有数了：<br>
#define va_arg(ap,t)&nbsp;&nbsp;&nbsp; ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )<br>
这个宏做了两个事情，<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ①用用户输入的类型名对参数地址进行强制类型转换，得到用户所需要的值<br>
&nbsp;&nbsp; ②计算出本参数的实际大小，将指针调到本参数的结尾，也就是下一个参数的首地址，以便后续处理。<br>
(5)
va_end宏的解释：x86平台定义为ap=(char*)0;使ap不再指向堆栈,而是跟NULL一样.有些直接定义为((void*)0),这样编
译器不会为va_end产生代码,例如gcc在linux的x86平台就是这样定义的. 在这里大家要注意一个问题:由于参数的地址用于
va_start宏,所以参数不能声明为寄存器变量或作为函数或数组类型. 关于va_start, va_arg,
va_end的描述就是这些了,我们要注意的 是不同的操作系统和硬件平台的定义有些不同,但原理却是相似的.<br>
<br>
(三)可变参数在编程中要注意的问题<br>
因为 va_start, va_arg, va_end等定义成宏,所以它显得很愚蠢,
可变参数的类型和个数完全在该函数中由程序代码控制,它并不能智能&nbsp; 地识别不同参数的个数和类型.
有人会问:那么printf中不是实现了智能识别参数吗?那是因为函数
printf是从固定参数format字符串来分析出参数的类型,再调用va_arg
的来获取可变参数的.也就是说,你想实现智能识别可变参数的话是要通过在自己的程序里作判断来实现的. 例如，在C 的经典教材《the c
programming language》的7.3节中就给出了一个printf的可能实现方式，由于篇幅原因这里不再叙述。<br>
（四）小结:<br>
1、标准C库的中的三个宏的作用只是用来确定可变参数列表中每个参数的内存地址，编译器是不知道参数的实际数目的。<br>
2、在实际应用的代码中，程序员必须自己考虑确定参数数目的办法，如<br>
⑴在固定参数中设标志—— printf函数就是用这个办法。后面也有例子。<br>
⑵在预先设定一个特殊的结束标记，就是说多输入一个可变参数，调用时要将最后一个可变参数的值设置成这个特殊的值，在函数体中根据这个值判断是否达到参数的结尾。本文前面的代码就是采用这个办法.<br>
无论采用哪种办法，程序员都应该在文档中告诉调用者自己的约定。<br>
3、实现可变参数的要点就是想办法取得每个参数的地址，取得地址的办法由以下几个因素决定：<br>
①函数栈的生长方向<br>
②参数的入栈顺序<br>
③CPU的对齐方式<br>
④内存地址的表达方式<br>
结合源代码，我们可以看出va_list的实现是由④决定的，_INTSIZEOF(n)的引入则是由③决定的，他和①②又一起决定了va_start的实现，最后va_end的存在则是良好编程风格的体现，将不再使用的指针设为NULL,这样可以防止以后的误操作。<br>
4、取得地址后，再结合参数的类型，程序员就可以正确的处理参数了。理解了以上要点，相信稍有经验的读者就可以写出适合于自己机器的实现来。下面臼且桓隼?<br>
（五）扩展——自己实现简单的可变参数的函数。<br>
下面是一个简单的printf函数的实现，参考了&lt;The C Programming Language&gt;中的156页的例子，读者可以结合书上的代码与本文参照。<br>
#include "stdio.h"<br>
#include "stdlib.h"<br>
void myprintf(char* fmt, ...)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //一个简单的类似于printf的实现，//参数必须都是int 类型<br>
{<br>
&nbsp;&nbsp;&nbsp; char*
pArg=NULL;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
//等价于原来的va_list<br>
&nbsp;&nbsp;&nbsp; char c;<br>
&nbsp; &nbsp;<br>
&nbsp;&nbsp;&nbsp; pArg = (char*)
&amp;fmt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
//注意不要写成p = fmt !!因为这里要对//参数取址，而不是取值<br>
&nbsp;&nbsp;&nbsp; pArg +=
sizeof(fmt);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
//等价于原来的va_start&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>
<br>
&nbsp;&nbsp;&nbsp; do<br>
&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c =*fmt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (c != '%')<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
putchar(c);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
//照原样输出字符<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>
{<br>
//按格式字符输出数据<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; switch(*++fmt)<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 'd':<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
printf("%d",*((int*)pArg));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 'x':<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("%#x",*((int*)pArg));<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; default:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pArg
+=
sizeof(int);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
//等价于原来的va_arg<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ++fmt;<br>
&nbsp;&nbsp;&nbsp; }while (*fmt != '\0');<br>
&nbsp;&nbsp;&nbsp; pArg =
NULL;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
//等价于va_end<br>
&nbsp;&nbsp;&nbsp; return;<br>
}<br>
int main(int argc, char* argv[])<br>
{<br>
&nbsp;&nbsp;&nbsp; int i = 1234;<br>
&nbsp;&nbsp;&nbsp; int j = 5678;<br>
&nbsp; &nbsp;<br>
&nbsp;&nbsp;&nbsp; myprintf("the first test:i=%d",i,j);<br>
&nbsp;&nbsp;&nbsp; myprintf("the secend test:i=%d; %x;j=%d;",i,0xabcd,j);<br>
&nbsp;&nbsp;&nbsp; system("pause");<br>
&nbsp;&nbsp;&nbsp; return 0;<br>
}<br>
在intel+win2k+vc6的机器执行结果如下：<br>
the first test:i=1234<br>
the secend test:i=1234; 0xabcd;j=5678;<br>
#include &lt;stdarg.h&gt;//不定数目参数需要的宏<br>
int max(int n,int num,...)<br>
{<br>
va_list x;//说明变量x<br>
va_start(x,num);//x被初始化为指向num后的第一个参数<br>
int m=num;<br>
for(int i=1;i&lt;n;i++)<br>
{<br>
//将变量x所指向的int类型的值赋给y,同时使x指向下一个参数<br>
int y=va_arg(x,int);<br>
if(y&gt;m)m=y;<br>
}<br>
va_end(x);//清除变量x<br>
return m;<br>
}<br>
main()<br>
{<br>
&nbsp;&nbsp;&nbsp; printf("%d,%d",max(3,5,56),max(6,0,4,32,45,533));<br>
}<br>
<br>
<br>
这是算最大值的，改一下就可以了。<br>
<br>
GNUC 提供了支持扩展选项的函数getopt_long<br>
在ansi c中只支持 -p 123这样的选项<br>
但是使用getopt_long我们可以扩展到--port=123这样的选项<br>
大家可以使用man getopt_long选项来查看使用方法<br>
下面这个是一个例子<br>
<br>
&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #include &lt;stdio.h&gt;&nbsp;&nbsp;&nbsp;&nbsp; /* for printf */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #include &lt;stdlib.h&gt;&nbsp;&nbsp;&nbsp; /* for exit */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #include &lt;getopt.h&gt;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; main (int argc, char **argv) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int c;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int digit_optind = 0;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (1) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
int this_option_optind = optind ? optind : 1;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
int option_index = 0;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
static struct option long_options[] = {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
{"add", 1, 0, 0},<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
{"append", 0, 0, 0},<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
{"delete", 1, 0, 0},<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
{"verbose", 0, 0, 0},<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
{"create", 1, 0, 'c'},<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
{"file", 1, 0, 0},<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
{0, 0, 0, 0}<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; };<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
c = getopt_long (argc, argv, "abc:d:012",<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
long_options, &amp;option_index);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (c == -1)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
break;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; switch (c) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 0:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
printf ("option %s", long_options[option_index].name);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (optarg)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
printf (" with arg %s", optarg);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
printf ("\n");<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
break;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case '0':<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case '1':<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case '2':<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (digit_optind != 0 &amp;&amp; digit_optind != this_option_optind)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
printf ("digits occur in two different argv-elements.\n");<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
digit_optind = this_option_optind;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
printf ("option %c\n", c);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
break;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 'a':<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
printf ("option a\n");<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
break;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 'b':<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
printf ("option b\n");<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
break;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 'c':<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
printf ("option c with value `%s'\n", optarg);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
break;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 'd':<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
printf ("option d with value `%s'\n", optarg);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
break;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case '?':<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
break;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; default:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
printf ("?? getopt returned character code 0%o ??\n", c);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (optind &lt; argc) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
printf ("non-option ARGV-elements: ");<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
while (optind &lt; argc)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
printf ("%s ", argv[optind++]);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf ("\n");<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exit (0);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<img src ="http://www.cnitblog.com/roguishangel/aggbug/4738.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/roguishangel/" target="_blank">牙刷</a> 2005-11-20 17:27 <a href="http://www.cnitblog.com/roguishangel/archive/2005/11/20/4738.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在main函数执行之前和执行之后执行的方法</title><link>http://www.cnitblog.com/roguishangel/archive/2005/11/20/4732.html</link><dc:creator>牙刷</dc:creator><author>牙刷</author><pubDate>Sun, 20 Nov 2005 09:17:00 GMT</pubDate><guid>http://www.cnitblog.com/roguishangel/archive/2005/11/20/4732.html</guid><wfw:comment>http://www.cnitblog.com/roguishangel/comments/4732.html</wfw:comment><comments>http://www.cnitblog.com/roguishangel/archive/2005/11/20/4732.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/roguishangel/comments/commentRss/4732.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/roguishangel/services/trackbacks/4732.html</trackback:ping><description><![CDATA[#include &lt;stdio.h&gt;<br>
#include &lt;stdlib.h&gt;<br>
<br>
static void before(void) __attribute__ ((constructor));<br>
static void after(void) __attribute__ ((destructor));<br>
static void middle(void);<br>
<br>
static void before()<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fprintf(stderr, "In %s %d\n", __func__, __LINE__);<br>
}<br>
<br>
static void after()<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fprintf(stderr, "In %s %d\n", __func__, __LINE__);<br>
}<br>
<br>
static void middle()<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fprintf(stderr, "In %s %d\n", __func__, __LINE__);<br>
}<br>
int main(void)<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; atexit(middle);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>
}<br>
<br>
通过指定<br>
static void before(void) __attribute__ ((constructor));<br>
表明这个函数应该在main之前执行<br>
<br>
static void after(void) __attribute__ ((destructor));<br>
表明函数在main之后执行<br>
<br>
atexit表明函数在退出的时候执行<img src ="http://www.cnitblog.com/roguishangel/aggbug/4732.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/roguishangel/" target="_blank">牙刷</a> 2005-11-20 17:17 <a href="http://www.cnitblog.com/roguishangel/archive/2005/11/20/4732.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>