📄 the linux gcc howto中译版v0_2 移植程式与编译程式.htm
字号:
name=index.42></A><CODE>sprintf()</CODE> <!--mstheme--></FONT></H3>
<P>在大部份的Unix系统上,<CODE>sprintf(string, fmt,
...)</CODE>传回的是<CODE>string</CODE>的指标,然而,这方面Linux(遵循ANSI)传回的却是放入string内的字元数目.进行移植时,尤其是针对SunOS,需有警觉的心。
<P>
<H3><!--mstheme--><FONT color=#cccccc><A name=index.49></A><A
name=index.48></A><A name=index.47></A><A name=index.46></A><A
name=index.45></A><A name=index.44></A><A
name=index.43></A><CODE>fcntl</CODE> 与相关的函数;<CODE>FD_*</CODE>家族的定义到底摆在哪里? <!--mstheme--></FONT></H3>
<P>就在<CODE><sys/time.h></CODE>里头。
为了真正的原型宣告,当你用了<CODE>fcntl</CODE>,可能你也想含括标头档<CODE><unistd.h></CODE>进来。
<P>一般而言,函数的manual page会在SYNOPSIS章节内列出需要的<CODE>标头档</CODE>。
<P>
<P>
<H3><!--mstheme--><FONT color=#cccccc><A
name=index.50></A><CODE>select()</CODE>的计时---程式执行时会处於忙碌-等待的状态 <!--mstheme--></FONT></H3>
<P>很久很久以前,,<CODE>select()</CODE>的计时参数只有唯读的性而已。即使到了最近,manual
pages仍然有下面这段的警告:
<P>
<BLOCKQUOTE>select()应该是藉由修正时间的数值(如果有的话),再传回自原始计时开始後所剩馀的时间。未来的版本可能会使这项功能实现。因此,就目前而言,若以为呼叫select()之後,计时指标仍然不会被修正过,可是一种非常不明智的想法喔!
</BLOCKQUOTE>
<P>未来就在我们的眼前了!至少,在这儿你绝对可以看到。函数<CODE>select()</CODE>传回的,是扣除等待尚未到达的资料所耗费的时间後,其剩馀的时间数值。如果在计时结束时,都没有资料传送进来,计时引数便会设为0;如果接著还有任何的select(),以同样的计时structure来呼叫,那麽select()便会立刻结束。
<P>若要修正这项问题,只要每次呼叫<CODE>select()</CODE>前,都把计时数值放到计时
structure内,就没有问题了。把下面的程式码,
<BLOCKQUOTE><CODE><!--mstheme--></FONT><PRE> struct timeval timeout;
timeout.tv_sec = 1; timeout.tv_usec = 0;
while (some_condition)
select(n,readfds,writefds,exceptfds,&timeout);
</PRE><!--mstheme--><FONT face=宋体></CODE></BLOCKQUOTE>改成,
<BLOCKQUOTE><CODE><!--mstheme--></FONT><PRE> struct timeval timeout;
while (some_condition) {
timeout.tv_sec = 1; timeout.tv_usec = 0;
select(n,readfds,writefds,exceptfds,&timeout);
}
</PRE><!--mstheme--><FONT face=宋体></CODE></BLOCKQUOTE>
<P>这个问题,在有些版本的Mosaic里是相当著名的,只要一次的等待,Mosaic就挂在那里了。Mosaic的萤幕右上角,是不是有个圆圆的、会旋转的地球动画。那颗球转得愈快,就表示资料从网路上传送过来的速率愈慢!
<P>
<H3><!--mstheme--><FONT color=#cccccc><A name=index.52></A><A
name=index.51></A>产生中断的系统呼叫 <!--mstheme--></FONT></H3>
<H3><!--mstheme--><FONT color=#cccccc>特徵:<!--mstheme--></FONT></H3>
<P>当一支程式以Ctrl-Z中止、然後再重新执行时□或者是其它可以产生Ctrl-C中断信号的情况,如子程序的终结等□系统就会抱怨说"interrupted
system call"或是"write: unknown error",或者诸如此类的讯息。
<P>
<H3><!--mstheme--><FONT color=#cccccc>问题点:<!--mstheme--></FONT></H3>
<P>POSIX的系统检查信号的次数,比起一些旧版的Unix是要多那麽一点。如果是Linux,可能就会执行signal handlers了□
<P><!--mstheme--></FONT><!--msthemelist-->
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0><!--msthemelist-->
<TBODY>
<TR>
<TD vAlign=baseline width=42><IMG height=15 hspace=13
src="The Linux GCC HOWTO中译版V0_2 移植程式与编译程式.files/zerbul1a.gif"
width=15></TD>
<TD vAlign=top width="100%"><!--mstheme--><FONT
face=宋体>非同步地(计时器的滴答声)<!--mstheme--></FONT><!--msthemelist--></TD></TR><!--msthemelist-->
<TR>
<TD vAlign=baseline width=42><IMG height=15 hspace=13
src="The Linux GCC HOWTO中译版V0_2 移植程式与编译程式.files/zerbul1a.gif"
width=15></TD>
<TD vAlign=top width="100%"><!--mstheme--><FONT face=宋体>系统呼叫的传回值<!--mstheme--></FONT><!--msthemelist--></TD></TR><!--msthemelist-->
<TR>
<TD vAlign=baseline width=42><IMG height=15 hspace=13
src="The Linux GCC HOWTO中译版V0_2 移植程式与编译程式.files/zerbul1a.gif"
width=15></TD>
<TD vAlign=top width="100%"><!--mstheme--><FONT
face=宋体>在下列系统呼叫的执行期间∶ <CODE>select()</CODE>, <CODE>pause()</CODE>,
<CODE>connect()</CODE>,<CODE>accept()</CODE>, <CODE>read()</CODE> on
terminals, sockets, pipes or files in <CODE>/proc</CODE>,
<CODE>write()</CODE> on terminals, sockets, pipes or the line
printer, <CODE>open()</CODE> on FIFOs, PTYs or serial
lines,<CODE>ioctl()</CODE> on terminals, <CODE>fcntl()</CODE> with
command <CODE>F_SETLKW</CODE>, <CODE>wait4()</CODE>,
<CODE>syslog()</CODE>, any TCP or NFS operations.
<!--mstheme--></FONT><!--msthemelist--></TD></TR><!--msthemelist--></TBODY></TABLE><!--mstheme--><FONT
face=宋体>
<P>就其它的作业系统而言,你需要的可能就是下面这些系统呼叫了: <CODE>creat()</CODE>,
<CODE>close()</CODE>, <CODE>getmsg()</CODE>, <CODE>putmsg()</CODE>,
<CODE>msgrcv()</CODE>, <CODE>msgsnd()</CODE>, <CODE>recv()</CODE>,
<CODE>send()</CODE>, <CODE>wait()</CODE>, <CODE>waitpid()</CODE>,
<CODE>wait3()</CODE>, <CODE>tcdrain()</CODE>, <CODE>sigpause()</CODE>,
<CODE>semop()</CODE> to this list.
<P>
<P>在系统呼叫期间,若有一信号(那支程式本身应准备好handler因应了)产生,handler就会被呼叫。当handler将控制权转移回系统呼叫时,它会侦测出它已经产生中断,而且传回值会立刻设定成-1,而<CODE>errno设定成EINTR</CODE>。程式并没有想到会发生这种事,所以就挂了。
<P>有两种修正的方法可以选择:
<P>(1) 对每个你自行安装的signal
handler,都须在sigaction的旗号加上<CODE>SA_RESTART</CODE>。例如,把下列的程式,
<P>
<BLOCKQUOTE><CODE><!--mstheme--></FONT><PRE> signal (sig_nr, my_signal_handler);
</PRE><!--mstheme--><FONT face=宋体></CODE></BLOCKQUOTE>改成,
<BLOCKQUOTE><CODE><!--mstheme--></FONT><PRE> signal (sig_nr, my_signal_handler);
{ struct sigaction sa;
sigaction (sig_nr, (struct sigaction *)0, &sa);
#ifdef SA_RESTART
sa.sa_flags |= SA_RESTART;
#endif
#ifdef SA_INTERRUPT
sa.sa_flags &= ~ SA_INTERRUPT;
#endif
sigaction (sig_nr, &sa, (struct sigaction *)0);
}
</PRE><!--mstheme--><FONT face=宋体></CODE></BLOCKQUOTE>
<P>要注意的是,当这部份的变更大量应用到系统呼叫之後,呼叫<CODE>read()</CODE>、<CODE>write()</CODE>、<CODE>ioctl()</CODE>、
<CODE>select()</CODE>、 <CODE>pause()</CODE> 与
<CODE>connect()</CODE>时,你仍然得自行检查<CODE>EINTR</CODE>。如下所示:
<P>(2) 你自己得很明确地检查<CODE>EINTR</CODE>:
<P>这里有两个针对<CODE>read()</CODE>与<CODE>ioctl()</CODE>的例子。
<P>
<P>原始的程式片段,使用<CODE>read()</CODE>:
<P>
<BLOCKQUOTE><CODE><!--mstheme--></FONT><PRE>int result;
while (len > 0) {
result = read(fd,buffer,len);
if (result < 0) break;
buffer += result; len -= result;
}
</PRE><!--mstheme--><FONT face=宋体></CODE></BLOCKQUOTE>修改成,
<BLOCKQUOTE><CODE><!--mstheme--></FONT><PRE>int result;
while (len > 0) {
result = read(fd,buffer,len);
if (result < 0) { if (errno != EINTR) break; }
else { buffer += result; len -= result; }
}
</PRE><!--mstheme--><FONT
face=宋体></CODE></BLOCKQUOTE>原始的程式片段,使用<CODE>ioctl()</CODE>:
<P>
<BLOCKQUOTE><CODE><!--mstheme--></FONT><PRE>int result;
result = ioctl(fd,cmd,addr);
</PRE><!--mstheme--><FONT face=宋体></CODE></BLOCKQUOTE>修改成,
<BLOCKQUOTE><CODE><!--mstheme--></FONT><PRE>int result;
do { result = ioctl(fd,cmd,addr); }
while ((result == -1) && (errno == EINTR));
</PRE><!--mstheme--><FONT face=宋体></CODE></BLOCKQUOTE>
<P>注意一点,有些版本的BSD Unix,其内定的行为是重新执行系统呼叫。若要让系统呼叫中断,得使用
<CODE>SV_INTERRUPT</CODE>或<CODE>SA_INTERRUPT</CODE>旗号。
<P>
<P>
<H3><!--mstheme--><FONT color=#cccccc><A name=index.56></A><A
name=index.55></A><A name=index.54></A><A name=index.53></A>可以写入的字串 <!--mstheme--></FONT></H3>
<P>gcc对其users总怀抱著乐观的想法,相信当他们打算让某个字串当作常数来用时---那它就真的只是字串常数而已。因此,这种字串常数会储存在程式码的记忆体区段内。这块区域可以page到磁碟机的image上,避免耗掉swap的记忆体空间,而且任何尝试写入的举动都会造成分页的错误(segmentation
fault)。这可是一种特色呢!
<P>对老旧一点的程式而言,这可能会产生一个问题。例如,呼叫<CODE>mktemp()</CODE>,传递的引数(arguments)是字串常数。
<CODE>mktemp()</CODE>会尝试著在*适当的位置*重新写入它的引数。
<P>修正的方法不外乎(a)以<CODE>-fwritable-strings</CODE>编译,迫使gcc将此常数置放在资料记忆体空间内;或者(b)将侵犯地权的部份重新改写,配置一个不为常数的字串,在呼叫前,先以strcpy()将资料拷贝进去。
<P>
<H3><!--mstheme--><FONT color=#cccccc><A
name=index.57></A>为什麽呼叫<CODE>execl()</CODE>会失败? <!--mstheme--></FONT></H3>
<P>那是因为你呼叫的方式不对。<CODE>execl</CODE>的第一个引数是你想要执行的程式名.第二个与接续的引数会变成你所呼叫的程式的<CODE>argv</CODE>阵列。记住:传统上,<CODE>argv[0]</CODE>是只有当程式没有带著引数执行时,才会有设定值。所以罗,你应该这样写:
<P>
<BLOCKQUOTE><CODE><!--mstheme--></FONT><PRE>execl("/bin/ls","ls",NULL);
</PRE><!--mstheme--><FONT face=宋体></CODE></BLOCKQUOTE>而不是只有,
<BLOCKQUOTE><CODE><!--mstheme--></FONT><PRE>execl("/bin/ls", NULL);
</PRE><!--mstheme--><FONT face=宋体></CODE></BLOCKQUOTE>
<P>
<P>执行程式而不带任何引数,可解释成是一种邀请函,目的是把此程式的动态程式库独立的特性印出来。至少,a.out是这样的。就ELF而言。事情就不是这样了.
<P>
<P>(如果你想得知此程式库的资讯,有一些更简单的介面可用;参考动态载入那一章节,或是<CODE>ldd</CODE>的manual page。)
<P>11/16/97译 6/2/98修正
<P>
<P><!--msthemeseparator-->
<P align=center><IMG height=10
src="The Linux GCC HOWTO中译版V0_2 移植程式与编译程式.files/zerrulea.gif"
width=600></P><A
href="http://lnwmm.xiloo.com/index3/linux/gcc/GCC-HOWTO-5.html">Next</A>
<A
href="http://lnwmm.xiloo.com/index3/linux/gcc/GCC-HOWTO-3.html">Previous</A>
<A
href="http://lnwmm.xiloo.com/index3/linux/gcc/GCC-HOWTO.html#toc4">Contents</A>
<!--mstheme--></FONT><!--msnavigation--></TD></TR><!--msnavigation--></TBODY></TABLE><!--msnavigation-->
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD><!--mstheme--><FONT face=宋体><!--msthemeseparator-->
<P align=center><IMG height=10
src="The Linux GCC HOWTO中译版V0_2 移植程式与编译程式.files/zerrulea.gif"
width=600></P>
<P align=center><FONT size=2>我是风所以我自由,我是我所以我存在<BR></FONT><FONT
size=1>----风一样的男子</FONT></P><!--mstheme--></FONT></TD></TR><!--msnavigation--></TBODY></TABLE></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -