2013-01-16 23 views
2

我的意思是像"(%d%%%d) some text %s , %d%% %x %o %#x %#o \n"这样的字符串。 printf家族的函数以某种方式知道他们需要从这个字符串得到多少个参数,因此不需要单独的参数。这个功能在c/C++中以单独的函数的形式提供,所以我可以编写自己的printf-like函数? (是的,我把这些百分比故意口音多么复杂它可以得到的,所以它不是百分比字符的简单计数)如何确定实现fprint格式化字符串需要多少个参数?

+0

别忘了'%*'! –

+3

您逐字地逐个查找字符串,查找后跟合法printf格式说明符的'%'字符并递增计数器。当你到达字符串末尾的'\ 0'时,你的计数器就是所需参数的个数。 –

回答

2

printf家庭的问题是,它是不是安全,它真正知道或者关心字符串或参数列表中有多少个格式元素。

printf家族使用一种称为“可变参数函数”的东西;只有一个参数被命名(格式字符串),而其他参数是从堆栈中取出的,而不考虑它们的类型或大小 - 它们的类型是从格式字符串中推导出来的,这使得它类型不安全,并且通过迭代使用多少个参数字符串并查找所有格式化说明符,这会使参数不安全。你可以写可变参数函数;语法是

void foo(...); 

,以后你可以用those macros and types,但如果你使用的是C++,你应该使用C++ 11个的可变参数模板而不是C可变参数的功能,如可变参数模板是类型安全的 - 你不要松键入信息在任何地方,并与universal references(但不完全是感谢他们)他们比可变参数功能更强大。

+0

匿名downvoter,谨慎解释? – Griwes

1

的功能printf系列只知道一个参数,第一个...

它基本上扫描串并在每次遇到它理解它就会从这种规模的再下一个参数格式说明时间参数列表...这是一个容易腐败的行为。 想象:

printf("%i",someInt); // fine 
printf("%i",someLong); // depending on endianness and sized 
         // of those types could be the high or low 32 bits(probably) 
printf("%i %i",someInt); // depending on abi could crash, read a int sized chunk 
         // of stack, or a register that would correspond to that 
         // parameter. 

所以本质上并不安全..
你应该注意的警告和编写可移植代码的时候做这样的事情:

size_t t = 5; //can be 32 or 64 bit depending on arch. 
printf("%ull",(unsigned long long)t); 

编辑。我想我只有一半回答了这个问题... 你可以定义你自己的可变参数函数,下面添加count个参数并返回结果。

int sumList(int count, ...); 
int main(int argc, const char * argv[]) 
{ 
    printf("the answer is: %i",sumList(4,1,2,3,4)); 
    return 0; 
} 
int sumList(int count, ...) 
{ 
    va_list args; 
    va_start(args, count); 
    int sum = 0; 
    for (int i = 0; i<count; i++) { 
     sum += va_arg(args, int); 
    } 
    va_end(args); 
    return sum; 
} 
+0

请注意,在某些主要编译器/系统上,'long'与'int'的大小相同,而在其他编译器/系统上则是'int'。'long long'是一个更好的例子,因为在大多数主要的编译器/系统上它比'int'更大。 –

1

不,没有用于解析printf样式格式字符串的标准库函数。如果你想编写自己的字符串格式化函数,那么我强烈建议不要遵循printf示例。在其他答案中提到的原因本质上是不安全的。由于词汇顺序在某些语言中发生更改,因此本地化也存在问题。就我个人而言,我会使用模板编写一个类型安全的函数,并复制.NET风格的字符串。 (其实,我确实做到了 - 这是很多工作,但也很有趣。)

相关问题