C中的PHP vsprintf()相当于什么?

时间:2011-09-03 12:25:06

标签: php c printf

我有这个PHP代码,并且出于性能原因需要C中的等价物。 我做过R& D Google;我没有得到任何解决方案。

代码是:

<?php
   $array = array('tom','jerry','cat'); //variable 
   $tmpl  = 'test %s for %s with %s'; //args taken from $array
   print vsprintf($tmpl,$array)."\n";
?>

5 个答案:

答案 0 :(得分:1)

如果你事先知道字符串,你可以手动展开数组:

char *array[] = {"tom", "jerry", "cat"};
char *tmpl = "test %s for %s with %s";
sprintf(out, tmpl, array[0], array[1], array[2])

要在C中动态执行此操作:

int my_sprintf(char * restrict out, const char * restrict format, int len, char **args){
    switch(len) {
        case 0: return sprintf(out, format);            
        case 1: return sprintf(out, format, args[0]);
        case 2: return sprintf(out, format, args[0], args[1]);
        case 3: return sprintf(out, format, args[0], args[1], args[2]);
        /* ... add more cases as necessary ... */
    }
    return -1;
}

你可能会深入研究GCC内部,但它不可移植。

用于生成相关代码的PHP脚本(这应该在编译之前运行):

int my_sprintf(char * restrict out, const char * restrict format, int len, char **args){
    switch(len) {
        <?php 
            for($i=0, $out="";$i<=100;++$i) { 
        ?>
        case <?= $i ?>: return sprintf(out, format <?= $out ?>);
        <?php 
            $out .= ", args[$i]"; 
            } 
        ?>
    }
}

答案 1 :(得分:1)

如果你知道你传递了多少个参数,你只需拨打snprintf(3)。如果您不知道,唯一的另一种选择是使用可变参数函数并调用vsnprintf。这通常用于将代码记录为snprintf周围的瘦包装器。例如:

void my_log_function(int level, const char *format, ...)
{
    if(level >= MIN_LOGGING_LEVEL)
    {
        va_list ap;
        va_start(ap, format);

        char buffer[4096];
        vsnprintf(buffer, sizeof(buffer), format, ap);
        // Now write buffer to a file/stdout/the debugger/etc.

        va_end(ap);
    }
}
...
my_log_function(LOG_LEVEL_DEBUG, "foo %d bar %s baz", 42, "quux");

如果确实只有数组中的参数,则无法使用标准C执行您想要的操作。您可以使用ffcall之类的库,但它不可移植到所有系统。例如,以下是使用ffcall执行此操作的方法:

int array_vsnprintf(char *str, size_t size, const char *format, int *args,
                    int numargs)
{
    av_alist alist;  // will hold the argument list
    int retval;  // will hold the return value from vsnprintf
    av_start_int(alist, &vsnprintf, &retval);

    // Add the arguments to the argument list.  This assumes all of the
    // arguments are ints -- if you have heterogeneous types, you need to keep
    // track of the type information somewhere and use the appropriate macro
    // for each argument.
    av_ptr(str);
    av_int(size);
    av_ptr(format);

    int i;
    for(i = 0; i < numargs; i++)
        av_int(alist, args[i]);

    // Now call vsnprintf
    av_call(alist);

    return retval;
}

答案 2 :(得分:0)

所以你想要一些从数组中打印参数的printf-variant?你不能用C语言做到这一点。

答案 3 :(得分:0)

与C中的vsprintf()的PHP变体没有直接的类比。有一个函数vsprintf() - 通常不应该使用它;使用vsnprintf()代替更安全。但是这不需要一系列字符指针,也不需要printf()的任何其他变体。

你有几个选择。 @Foo Bah概述的那个是这样做的一种方式;复杂的因素是你必须写出30-70个变种,如果没有别的话,那就是丑陋的。

我认为在这种情况下,我会编写一个解析格式字符串并处理数组的变体。它会将格式的文字组件复制到结果中,然后在请求时调用snprintf()格式化(复制)数组中的元素。我注意到像%*.*s这样的格式在上下文中不是一个选项;没有办法获得传递的整数值(或者没有 clean 方式)。并且没有简单的方法来支持交错格式说明符,例如%f%d。接口设计中一个有趣的问题是“你传递数组的长度并验证长度和格式,还是让格式确定数组的长度”?

int vsnprintfas(char *buffer, size_t buflen, const char *format,
                size_t arrlen, char * const * const array);

或者:

int vsnprintfas(char *buffer, size_t buflen, const char *format,
                char * const * const array);

由于存在错误的余地,我会使用双重检查界面 - 列出的第一个界面。当然,建议的as后缀用于字符串数组。我非常愿意在const上就array限定符的数量和位置进行协商,但从概念上讲,它是一组指针,函数根本不会改变。

答案 4 :(得分:0)

我已经尝试过这种替代工作正常,比如把'att'作为'|'分隔的字符串和补丁 如果可能的话,我可以进一步优化这个,这有任何瓶颈。

 char *tmpl = "test %s for %s with %s" , buffer[10000], *attrs="Tom|Jerry|Cat";

 tmplpatch(buffer,tmpl,attrs);
 printf("%s\n",buffer);

void tmplpatch(char *str, const char *fmt, const char *attrs) {
  for(;*str=*fmt, *fmt;++fmt,++str) {
   if(*fmt == '\\') {
     fmt++;*str=*fmt;continue;
   }
   if(!(*fmt == '%' && *(fmt+1)=='s')) continue; // ! %s
   for(;*attrs!='\0' && *attrs != '|';*str++=*attrs++);
   ++fmt;++attrs;str--; // skip s, |, junk not '\0'
  }
}