QQ登录

只需一步,快速开始

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 1257|回复: 10

『新手请教』 学习《UNIX环境高级编程》遇到的几个问题。

[复制链接]
发表于 2005-11-4 00:00:06 | 显示全部楼层 |阅读模式
我刚刚开始看这本书,看到了第二章,遇到了几个问题。请各位指教一下,谢谢了。

第一个问题:
在第一章的课后习题中,1.4:
对于出错处理函数err_sys,当调用该函数时,保存了errno的值。为什么?
其中函数原型是:
void
err_sys(const char *fmt,...)
{
      va_list         ap;
      va_start(ap,fmt);
      err_doit(1,fmt,ap);
      va_end(ap);
      exit(1);
}
其中,
static void
err_doit(int errnoflag, const char *fmt, va_list ap)
{
      int                  errno_save;
      char               buf[MAXLIZE];
      
      errno_save=errno;
      vsprintf(buf, fmt, ap);
      if(errnoflag)
             sprintf(buf+strlen(buf), ": %s", strerror(errno_save));
      strcat(buf, "\n");
      fflush(stdout);
      fputs(buf,stderr);
      fflush(NULL);
      return;
}
在他的习题答案中是这样解释的:
调用ffush, fprintf, vprintf函数可修改errno的值。如果它的值改变了没有保存,则最终显示的出错信息是不正确的。
  他还举了一个不保存errno的例子:
#include<stdio.h>
int
main()
{
      int   fd;
      extern int errno;
      if ( ( fd = open( "no/such/file", 0)) < 0){
            printf("open error:");
            printf( "errno = %d\n", errno);
      }
      exit(0);
}
执行上面的程序,结果为:

$ grep BSD /etc/motd
   4.3 BSD UNIX #29:.......
$ a.out
   open error :errno=2                 工作正常,stdout是一个终端
$ a.out >temp.foo
   open error :errno=25               错误


我的问题是:

首先,什么叫做”保存errno的值”
其次,为什么说err_sys保存了errno的值
最后,为什么说上面这个例子没有保存errno的值,正确的errno=?
 楼主| 发表于 2005-11-4 00:00:46 | 显示全部楼层
我的第二个问题是:

在2.5 节中,关于“限制”中提到:
  
编译时间限制(短整型的最大值是多少)
执行时间限制(文件名的最大字符数是多少)

为什么说,短整型的最大值是多少 是 编译时间限制(的实例)
为什么说,文件名的最大字符数是多少 是 执行时间限制(的实例)
回复

使用道具 举报

发表于 2005-11-4 02:58:39 | 显示全部楼层
>> 首先,什么叫做”保存errno的值”
int old_errno = errno;
之后输出 old_errno 而不是 errno 的值

>> 其次,为什么说err_sys保存了errno的值
影印版 P684 Program B.2 中最后一个函数[code:1]static void err_doit(...[/code:1] 中,变量声明之后的第一行代码,看后面的注释。
>> 最后,为什么说上面这个例子没有保存errno的值,正确的errno=?
上面的代码中 open( "no/such/file", 0 ) 设置的 errno 被 printf 中的过程覆盖了,因此会出现 errno == 0 的奇怪情况。关于 open(2) 的出错情况请参考 open(2) 手册页(man 2 open)

>> 为什么说,短整型的最大值是多少 是 编译时间限制(的实例)
C语言和编译器限制,不可调整
>> 为什么说,文件名的最大字符数是多少 是 执行时间限制(的实例)
系统配置相关,可调整。
回复

使用道具 举报

 楼主| 发表于 2005-11-5 10:19:33 | 显示全部楼层
errno == 0??
楼上是不是写错了?
我的理解是:
本来open打开错误返回errno是另外一个数ENOENT,
由于printf的关系使得errno=2了。
对不对?

再问个问题,象ENOENT,ENOTTY这些常数在哪能查到?
回复

使用道具 举报

发表于 2005-11-5 21:24:50 | 显示全部楼层
工作正常
以为就是 errno == 0 了  
简单的说,就是 printf (或printf中调用的某些系统调用或库函数)会覆盖errno的值。

对于所有可能设置errno值的 syscall / lib function,man page 中都有专门的一节说明会有哪些可能的值。我认为,只知道一个错误而不知道它的来处是完全没有意义的事情……   
回复

使用道具 举报

 楼主| 发表于 2005-11-6 13:57:52 | 显示全部楼层
我把程序改了一下:
#include<stdio.h>
int
main()
{
int fd;
int errnosave;
extern int errno;
if ( ( fd = open( "no/such/file", 0)) < 0){
errnosave=errno;
printf( "errno = %d\n", errnosave);

printf("open error:");
printf( "errno = %d\n", errno);
}
exit(0);
}
执行a.out
结果输出:
errno=2
open error:errno=2
这岂不是说明,printf没有改变errno的值吗?
回复

使用道具 举报

发表于 2005-11-6 14:02:36 | 显示全部楼层
印象中,函数调用出错可能设置 errno 为某个特定值,但是调用成功的时候不会恢复 errno 为 0。
回复

使用道具 举报

 楼主| 发表于 2005-11-6 14:56:32 | 显示全部楼层
这个问题我解决了:
对于errno要知道两天原则:
1.如果没有出错,则其值不会被一个例程清除,因此,仅当函数的返回值指明出错时,才检查其值。

2.没有任何一个函数可以把errno设置为0。<errno.h>中定义的所有常数都不是0;

谢谢你了。呵呵
你是不是看完了《unix环境高级编程》,以后要好好请教你啊。
回复

使用道具 举报

发表于 2005-11-6 14:58:28 | 显示全部楼层
呵呵。。。我是把 APUE 影印版的 目录和索引 看完了,中间的就随便查了……:)
一起进步吧。
回复

使用道具 举报

 楼主| 发表于 2005-11-6 15:25:19 | 显示全部楼层
在APUE11.9中的一个程序11-5是用来验证isatty函数,文件描述符是不是引用一个终端设备。
其中他给的两个例子,
a.out
fd 0 :tty
...


a.out </etc/passwd  2>/dev/dull
.....
...
我不明白的是,程序终端文件描述符0,1,2
isatty(0)
isatty(1)
isatty(2)
都是怎么确定的?
特别是对
a.out </etc/passwd  2>/dev/dull

能帮我分析一下吗?
呵呵,我的基础是差了点。谢谢了
回复

使用道具 举报

发表于 2005-11-6 15:39:54 | 显示全部楼层
当调用 fork(2) 的时候,派生出的子进程会将父进程的所有 fd 复制一遍给子进程。也就是说,父进程中 0,1,2 (以及之后的 3,4,5,6……)这些 fd 分别引用到哪个文件(设备),子进程都会得到这些 fd 的副本。

具体可以参考 fork 的文档;相关的还有 dup / dup2。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

GMT+8, 2024-11-3 04:13 , Processed in 0.039855 second(s), 15 queries .

© 2021 Powered by Discuz! X3.5.

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