我有这个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";
?>
答案 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'
}
}