免费注册 查看新帖 |

Chinaunix

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

[printf 探索] 为什么printf不是可重入函数? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-11-15 14:22 |只看该作者 |倒序浏览
前面有版友提出printf族的函数是non reentrant的,所以在信号处理函数中使用是不安全的,俺也参与了讨论
http://linux.chinaunix.net/bbs/viewthread.php?tid=1142533&extra=
但是没有搞清楚具体是为什么

前两天正好看到一段文字,提到printf可以调用一些call back函数
OMG
这实在太令人吃惊了
如果printf可以调用call back函数,这些函数如果访问static/global变量都是可能的,那么printf作为non reentrant就没有疑问了

现在问题变成了探讨printf如何使用call back函数,这是本文的主要目的

查看了一些文档,原来是这么回事
GNU C库中的printf允许自定义格式化字符串,如何处理这些自定义的格式化字符串就是通过用户提供call back函数进行的

什么是自定义格式化字符串呢?
我们知道printf("%i",  i)会把i作为integer打印出来,这个%i就是一个格式化字符串,这是printf提供给我们的格式化串
那我们为什么要自定义呢,举个例子
假如现在有这么一个结构

  1.      typedef struct
  2.      {
  3.        char *name;
  4.      }
  5.      Widget;
  6.      Widget mywidget;
  7.      mywidget.name = "mywidget";
复制代码

想打印这个结构体的地址以及名字的话,当然可以这样写
printf("%p\t%s\n", &mywidget, mywidget.name);
但是如果有很多这样的语句,我们就会希望有一种更方便的形式了
比如直接来个
printf ("%W\n", &mywidget);
就能够打印所有需要的内容
这就可以通过自定义一个新的%W格式化串来实现

下面是一个完整的例子,摘自
http://www.gnu.org/software/hell ... f-Extension-Example
有兴趣的编译运行一下就知道这个自定义格式化串的用法了

更多信息见
http://www.gnu.org/software/hell ... omizing-Printf.html

/*我想用C代码模式来着,但是不知道是服务器还是我的浏览器的原因,总是打不开代码模式的窗口,老是弹出http://www.chinaunix.net/hot.shtml*/

  1.      #include <stdio.h>
  2.      #include <stdlib.h>
  3.      #include <printf.h>
  4.      
  5.      typedef struct
  6.      {
  7.        char *name;
  8.      }
  9.      Widget;
  10.      
  11.      int
  12.      print_widget (FILE *stream,
  13.                    const struct printf_info *info,
  14.                    const void *const *args)
  15.      {
  16.        const Widget *w;
  17.        char *buffer;
  18.        int len;
  19.      
  20.        /* Format the output into a string. */
  21.        w = *((const Widget **) (args[0]));
  22.        len = asprintf (&buffer, "<Widget %p: %s>", w, w->name);
  23.        if (len == -1)
  24.          return -1;
  25.      
  26.        /* Pad to the minimum field width and print to the stream. */
  27.        len = fprintf (stream, "%*s",
  28.                       (info->left ? -info->width : info->width),
  29.                       buffer);
  30.      
  31.        /* Clean up and return. */
  32.        free (buffer);
  33.        return len;
  34.      }
  35.      
  36.      
  37.      int
  38.      print_widget_arginfo (const struct printf_info *info, size_t n,
  39.                            int *argtypes)
  40.      {
  41.        /* We always take exactly one argument and this is a pointer to the
  42.           structure.. */
  43.        if (n > 0)
  44.          argtypes[0] = PA_POINTER;
  45.        return 1;
  46.      }
  47.      
  48.      
  49.      int
  50.      main (void)
  51.      {
  52.        /* Make a widget to print. */
  53.        Widget mywidget;
  54.        mywidget.name = "mywidget";
  55.      
  56.        /* Register the print function for widgets. */
  57.        register_printf_function ('W', print_widget, print_widget_arginfo);
  58.      
  59.        /* Now print the widget. */
  60.        printf ("|%W|\n", &mywidget);
  61.        printf ("|%35W|\n", &mywidget);
  62.        printf ("|%-35W|\n", &mywidget);
  63.      
  64.        return 0;
  65.      }
复制代码

[ 本帖最后由 lemoncookie 于 2009-11-15 14:24 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2009-11-15 16:21 |只看该作者
没有 那么复杂吧 ! printf   可以看成 write + vsprintf()    2个 函数的封装  问题肯定是 vsprintf

要不自己写个 呵呵

论坛徽章:
0
3 [报告]
发表于 2009-11-17 13:42 |只看该作者

回复 #2 masonzhang 的帖子

是没有什么复杂的
我只是吃惊于printf可以调用call back函数
当然,这只是glibc的实现方式,并非标准中指定的

论坛徽章:
0
4 [报告]
发表于 2009-11-17 16:56 |只看该作者
用C多年,不知有此用法。学习一下

论坛徽章:
84
每日论坛发贴之星
日期:2015-12-29 06:20:00每日论坛发贴之星
日期:2016-01-16 06:20:00每周论坛发贴之星
日期:2016-01-17 22:22:00程序设计版块每日发帖之星
日期:2016-01-20 06:20:00每日论坛发贴之星
日期:2016-01-20 06:20:00程序设计版块每日发帖之星
日期:2016-01-21 06:20:00每日论坛发贴之星
日期:2016-01-21 06:20:00程序设计版块每日发帖之星
日期:2016-01-23 06:20:00程序设计版块每日发帖之星
日期:2016-01-31 06:20:00数据库技术版块每日发帖之星
日期:2016-01-16 06:20:00程序设计版块每日发帖之星
日期:2016-01-16 06:20:00程序设计版块每日发帖之星
日期:2016-01-14 06:20:00
5 [报告]
发表于 2009-11-21 16:20 |只看该作者
因为 printf 操作的 stdout 是个全局共享资源!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP