免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3110 | 回复: 2
打印 上一主题 下一主题

[函数] 求教一段纠结的函数代码 [复制链接]

论坛徽章:
11
摩羯座
日期:2013-09-29 17:39:09白羊座
日期:2014-11-13 09:38:14技术图书徽章
日期:2014-01-17 15:07:36狮子座
日期:2013-12-25 14:01:52技术图书徽章
日期:2013-12-17 11:33:22技术图书徽章
日期:2013-12-03 10:27:57天秤座
日期:2013-11-08 15:47:19申猴
日期:2013-10-29 13:16:32未羊
日期:2013-10-12 22:28:56辰龙
日期:2013-10-09 14:39:5515-16赛季CBA联赛之山东
日期:2016-07-25 10:23:00
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2012-12-18 17:55 |只看该作者 |倒序浏览
本帖最后由 superwujc 于 2012-12-18 17:57 编辑

下列代码有些又臭又长,摘自《The Linux Programming Interface》第4章,Page84,文件名为seek_io.c;我把它拼凑到了一起,没办法,小弟水平太菜,不知道怎样发问

先说一下代码功能:验证Linux系统调用open(),read(),write()和lseek(),第一个命令行参数指定将要被打开的文件,其余的参数指定将要在文件上执行的IO操作,每个操作包含一个  字母+数值  的形式
s表示偏移量,r表示从当前偏移量读取并以文本形式打印,R表示从当前偏移量读取并以十六进制形式打印,这3个参数都后跟表示字节长度的数值,w表示写入字符,后跟指定的字符串

如,seek_io myfile wxyz s1 r2   表示打开(或新建)myfile文件,在当前偏移量写入字符xyz,从文件开始处设置1字节的偏移量后,读取2个字节

由于里面细节有些复杂,说一下具体疑问:
在main()中执行到if (-1 == fd)判断文件是否打开或创建成功时,调用了errExit()函数,而errExit()函数又调用了outputError()函数,但是想不通这个outputError()函数是干什么用的,为什么直接调用先前定义的Boolean类型,而且是直接使用TRUE
烦请哪位大神,帮忙解释一下if (-1 == fd)时,调用errExit()函数和outputError()函数处理的具体思路和具体步骤吗?不胜感激!!!


头文件和函数声明部分
  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <fcntl.h>
  5. #include <unistd.h>
  6. #include <string.h>
  7. #include <stdlib.h>
  8. #include <errno.h>
  9. #include <stdarg.h>
  10. #include "ename.c.inc"
  11. #include <ctype.h>    //declaration for character test & map function

  12. #define GN_NONNEG       01      /* Value must be >= 0 */
  13. #define GN_GT_0         02      /* Value must be > 0 */

  14. #define GN_ANY_BASE   0100      /* Can use any base - like strtol(3) */
  15. #define GN_BASE_8     0200      /* Value is expressed in octal */
  16. #define GN_BASE_16    0400      /* Value is expressed in hexadecimal */

  17. typedef enum { FALSE, TRUE } Boolean;

  18. void usageErr(const char *format, ...);
  19. void errExit(const char *format, ...);
  20. void cmdLineErr(const char *format, ...);
  21. static void terminate(Boolean useExit3);
  22. static void outputError(Boolean useErr, int err, Boolean flushStdout,
  23.         const char *format, va_list ap);

  24. static void gnFail(const char *fname, const char *msg, const char *arg, const char *name);
  25. long getLong(const char *arg, int flags, const char *name);
  26. static long getNum(const char *fname, const char *arg, int flags, const char *name);
复制代码
ename.c.inc部分
  1. static char *ename[] = {
  2.     /*   0 */ "",
  3.     /*   1 */ "EPERM", "ENOENT", "ESRCH", "EINTR", "EIO", "ENXIO",
  4.     /*   7 */ "E2BIG", "ENOEXEC", "EBADF", "ECHILD",
  5.     /*  11 */ "EAGAIN/EWOULDBLOCK", "ENOMEM", "EACCES", "EFAULT",
  6.     /*  15 */ "ENOTBLK", "EBUSY", "EEXIST", "EXDEV", "ENODEV",
  7.     /*  20 */ "ENOTDIR", "EISDIR", "EINVAL", "ENFILE", "EMFILE",
  8.     /*  25 */ "ENOTTY", "ETXTBSY", "EFBIG", "ENOSPC", "ESPIPE",
  9.     /*  30 */ "EROFS", "EMLINK", "EPIPE", "EDOM", "ERANGE",
  10.     /*  35 */ "EDEADLK/EDEADLOCK", "ENAMETOOLONG", "ENOLCK", "ENOSYS",
  11.     /*  39 */ "ENOTEMPTY", "ELOOP", "", "ENOMSG", "EIDRM", "ECHRNG",
  12.     /*  45 */ "EL2NSYNC", "EL3HLT", "EL3RST", "ELNRNG", "EUNATCH",
  13.     /*  50 */ "ENOCSI", "EL2HLT", "EBADE", "EBADR", "EXFULL", "ENOANO",
  14.     /*  56 */ "EBADRQC", "EBADSLT", "", "EBFONT", "ENOSTR", "ENODATA",
  15.     /*  62 */ "ETIME", "ENOSR", "ENONET", "ENOPKG", "EREMOTE",
  16.     /*  67 */ "ENOLINK", "EADV", "ESRMNT", "ECOMM", "EPROTO",
  17.     /*  72 */ "EMULTIHOP", "EDOTDOT", "EBADMSG", "EOVERFLOW",
  18.     /*  76 */ "ENOTUNIQ", "EBADFD", "EREMCHG", "ELIBACC", "ELIBBAD",
  19.     /*  81 */ "ELIBSCN", "ELIBMAX", "ELIBEXEC", "EILSEQ", "ERESTART",
  20.     /*  86 */ "ESTRPIPE", "EUSERS", "ENOTSOCK", "EDESTADDRREQ",
  21.     /*  90 */ "EMSGSIZE", "EPROTOTYPE", "ENOPROTOOPT",
  22.     /*  93 */ "EPROTONOSUPPORT", "ESOCKTNOSUPPORT",
  23.     /*  95 */ "EOPNOTSUPP/ENOTSUP", "EPFNOSUPPORT", "EAFNOSUPPORT",
  24.     /*  98 */ "EADDRINUSE", "EADDRNOTAVAIL", "ENETDOWN", "ENETUNREACH",
  25.     /* 102 */ "ENETRESET", "ECONNABORTED", "ECONNRESET", "ENOBUFS",
  26.     /* 106 */ "EISCONN", "ENOTCONN", "ESHUTDOWN", "ETOOMANYREFS",
  27.     /* 110 */ "ETIMEDOUT", "ECONNREFUSED", "EHOSTDOWN", "EHOSTUNREACH",
  28.     /* 114 */ "EALREADY", "EINPROGRESS", "ESTALE", "EUCLEAN",
  29.     /* 118 */ "ENOTNAM", "ENAVAIL", "EISNAM", "EREMOTEIO", "EDQUOT",
  30.     /* 123 */ "ENOMEDIUM", "EMEDIUMTYPE", "ECANCELED", "ENOKEY",
  31.     /* 127 */ "EKEYEXPIRED", "EKEYREVOKED", "EKEYREJECTED",
  32.     /* 130 */ "EOWNERDEAD", "ENOTRECOVERABLE", "ERFKILL"
  33. };

  34. #define MAX_ENAME 132
复制代码
main部分
  1. int main (int argc, char *argv[])
  2. {
  3.         size_t len;
  4.         off_t offset;
  5.         int fd, ap, j;
  6.         char *buf;
  7.         ssize_t numRead, numWritten;

  8.         if (argc < 3 || 0 == strcmp(argv[1], "--help"))
  9.         {
  10.                 usageErr ("%s file {r<length>|R<length>|w<string>|s<offset>}...\n", argv[0]);//only two arguments
  11.         }

  12.         fd = open (argv[1], O_RDWR | O_CREAT,
  13.                                 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);//rw-rw-rw
  14.        
  15.         if (-1 == fd)
  16.         {
  17.                 errExit ("open");
  18.         }
  19.        
  20.         for (ap = 2; ap  < argc; ap++)
  21.         {
  22.                 switch (argv[ap][0])
  23.                 {
  24.                         case 'r':
  25.                         case 'R':
  26.                                 len = getLong (&argv[ap][1], GN_ANY_BASE, argv[ap]);

  27.                                 buf = malloc (len);
  28.                                 if (NULL == buf)
  29.                                 {
  30.                                         errExit ("malloc");
  31.                                 }

  32.                                 numRead = read (fd, buf, len);
  33.                                 if (-1 == numRead)
  34.                                 {
  35.                                         errExit ("read");
  36.                                 }

  37.                                 if (0 == numRead)
  38.                                 {
  39.                                         printf ("%s: end-of-file\n", argv[ap]);
  40.                                 } else
  41.                                 {
  42.                                         printf ("%s: ", argv[ap]);
  43.                                         for (j = 0; j < numRead; j++)
  44.                                         {
  45.                                                 if ('r' == argv[ap][0])
  46.                                                 {
  47.                                                         printf ("%c", isprint((unsigned char) buf[j]) ?
  48.                                                                                                         buf[j] : '?');
  49.                                                 } else
  50.                                                 {
  51.                                                         printf ("%02x ", (unsigned int) buf[j]);
  52.                                                 }
  53.                                         }
  54.                                         printf ("\n");
  55.                                 }

  56.                                 free (buf);
  57.                                 break;
  58.                         case 'w':
  59.                                 numWritten  = write (fd, &argv[ap][1], strlen (&argv[ap][1]));
  60.                                 if (-1 == numWritten)
  61.                                 {
  62.                                         errExit ("write");
  63.                                 }
  64.                                 printf ("%s: wrote %ld bytes\n", argv[ap], (long) numWritten);
  65.                                 break;
  66.                         case 's':
  67.                                 offset = getLong (&argv[ap][1], GN_ANY_BASE, argv[ap]);
  68.                                 if (-1 == lseek (fd, offset, SEEK_SET))
  69.                                 {
  70.                                         errExit ("lseek");
  71.                                 }
  72.                                 printf ("%s: seek succeeded\n", argv[ap]);
  73.                                 break;
  74.                         default:
  75.                                 cmdLineErr ("Argument must start with [rRws]: %s\n", argv[ap]);
  76.                 }
  77.         }
  78.         exit (EXIT_SUCCESS);
  79. }
复制代码
其他函数部分
  1. void usageErr(const char *format, ...)
  2. {
  3.     va_list argList;

  4.     fflush(stdout);           /* Flush any pending stdout */

  5.     fprintf(stderr, "Usage: ");
  6.     va_start(argList, format);
  7.     vfprintf(stderr, format, argList);
  8.     va_end(argList);

  9.     fflush(stderr);           /* In case stderr is not line-buffered */
  10.     exit(EXIT_FAILURE);
  11. }

  12. void errExit(const char *format, ...)
  13. {
  14.     va_list argList;

  15.     va_start(argList, format);
  16.     outputError(TRUE, errno, TRUE, format, argList);
  17.     va_end(argList);

  18.     terminate(TRUE);
  19. }


  20. void terminate(Boolean useExit3)
  21. {
  22.     char *s;

  23.     /* Dump core if EF_DUMPCORE environment variable is defined and
  24.        is a nonempty string; otherwise call exit(3) or _exit(2),
  25.        depending on the value of 'useExit3'. */

  26.     s = getenv("EF_DUMPCORE");

  27.     if (s != NULL && *s != '\0')
  28.         abort();
  29.     else if (useExit3)
  30.         exit(EXIT_FAILURE);
  31.     else
  32.         _exit(EXIT_FAILURE);
  33. }

  34. void cmdLineErr(const char *format, ...)
  35. {
  36.     va_list argList;

  37.     fflush(stdout);           /* Flush any pending stdout */

  38.     fprintf(stderr, "Command-line usage error: ");
  39.     va_start(argList, format);
  40.     vfprintf(stderr, format, argList);
  41.     va_end(argList);

  42.     fflush(stderr);           /* In case stderr is not line-buffered */
  43.     exit(EXIT_FAILURE);
  44. }

  45. long getNum(const char *fname, const char *arg, int flags, const char *name)
  46. {
  47.     long res;
  48.     char *endptr;
  49.     int base;

  50.     if (arg == NULL || *arg == '\0')
  51.         gnFail(fname, "null or empty string", arg, name);

  52.     base = (flags & GN_ANY_BASE) ? 0 : (flags & GN_BASE_8) ? 8 :
  53.                         (flags & GN_BASE_16) ? 16 : 10;

  54.     errno = 0;
  55.     res = strtol(arg, &endptr, base);
  56.     if (errno != 0)
  57.         gnFail(fname, "strtol() failed", arg, name);

  58.     if (*endptr != '\0')
  59.         gnFail(fname, "nonnumeric characters", arg, name);

  60.     if ((flags & GN_NONNEG) && res < 0)
  61.         gnFail(fname, "negative value not allowed", arg, name);

  62.     if ((flags & GN_GT_0) && res <= 0)
  63.         gnFail(fname, "value must be > 0", arg, name);

  64.     return res;
  65. }

  66. void gnFail(const char *fname, const char *msg, const char *arg, const char *name)
  67. {
  68.     fprintf(stderr, "%s error", fname);
  69.     if (name != NULL)
  70.         fprintf(stderr, " (in %s)", name);
  71.     fprintf(stderr, ": %s\n", msg);
  72.     if (arg != NULL && *arg != '\0')
  73.         fprintf(stderr, "        offending text: %s\n", arg);

  74.     exit(EXIT_FAILURE);
  75. }

  76. void outputError(Boolean useErr, int err, Boolean flushStdout,
  77.         const char *format, va_list ap)
  78. {
  79. #define BUF_SIZE 500
  80.     char buf[BUF_SIZE], userMsg[BUF_SIZE], errText[BUF_SIZE];

  81.     vsnprintf(userMsg, BUF_SIZE, format, ap);

  82.     if (useErr)
  83.         snprintf(errText, BUF_SIZE, " [%s %s]",
  84.                 (err > 0 && err <= MAX_ENAME) ?
  85.                 ename[err] : "?UNKNOWN?", strerror(err));
  86.     else
  87.         snprintf(errText, BUF_SIZE, ":");

  88.     snprintf(buf, BUF_SIZE, "ERROR%s %s\n", errText, userMsg);

  89.     if (flushStdout)
  90.         fflush(stdout);       /* Flush any pending stdout */
  91.     fputs(buf, stderr);
  92.     fflush(stderr);           /* In case stderr is not line-buffered */
  93. }

  94. long getLong(const char *arg, int flags, const char *name)
  95. {
  96.     return getNum("getLong", arg, flags, name);
  97. }
复制代码

论坛徽章:
0
2 [报告]
发表于 2012-12-18 18:30 |只看该作者
userMsg,是你调用errExit穿进去的字符串
errText是是标准库内部产生的错误,通过strerror(err)获取,err是标准库定义的全局变量errno传过来的,useErr用来标识是否打印这个错误
最后把这两个错误信息合并打印

有点不太理解这段
if (flushStdout)
        fflush(stdout);       /* Flush any pending stdout */
下面反正是要fflush的,为什么还要多调用一次fflush,这是出于什么考虑,有人能解答一下吗?

论坛徽章:
0
3 [报告]
发表于 2012-12-18 20:19 |只看该作者
useErr 设置为 TRUE 的话, 输出详细的错误信息—— 使用ename数组吧errno翻译为字符串,并用strerror获得原因。 然后再附加上userMsg, 否则的话只有userMsg。
这里作者直接用TRUE可能是想让errExit输出详细的错误信息。

最后fflush标准输出和标准错误输出
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP