使用 stdargs (va_start) 的 C 程序的奇怪行为 (SEGFAULT)
我编写了一个可变参数 C 函数,其任务是为缓冲区分配所需的内存,然后 sprintf 在该缓冲区中提供给该函数的参数。但我看到了它的奇怪行为。它只能工作一次。如果我对这个函数有两次调用,它就会出现段错误。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
char *xsprintf(char * fmt, ...)
{
va_list ap;
char *part;
char *buf;
size_t len = strlen(fmt)+1;
va_start(ap, fmt);
while (part = va_arg(ap, char *))
len += strlen(part);
va_end(ap);
buf = (char*) malloc(sizeof(char)*len);
va_start(ap, fmt);
vsprintf(buf, fmt, ap);
va_end(ap);
return buf;
}
int main(int argc, const char *argv[])
{
char *b;
b = xsprintf("my favorite fruits are: %s, %s, and %s", "coffee", "C", "oranges");
printf("size de buf is %d\n", strlen(b)); //this works. After it, it segfaults.
/*
free(b);
b = NULL;
*/
b = xsprintf("my favorite fruits are: %s, %s, and %s", "coffee", "C", "oranges");
printf("size de buf is %d\n", strlen(b));
printf("%s", b);
return 0;
}
这是该程序的输出:
size de buf is 46
[1] 4305 segmentation fault ./xsprintftest
我做错了什么吗?我不应该在一个函数中多次使用 va_start
吗?你还有其他选择吗?多谢! :)
I wrote a variadic C function which mission is to allocate the needed memory for a buffer, and then sprintf the args given to this function in that buffer. But I'm seeing a strange behavior with it. It works only once. If I have two calls for this function it segfaults.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
char *xsprintf(char * fmt, ...)
{
va_list ap;
char *part;
char *buf;
size_t len = strlen(fmt)+1;
va_start(ap, fmt);
while (part = va_arg(ap, char *))
len += strlen(part);
va_end(ap);
buf = (char*) malloc(sizeof(char)*len);
va_start(ap, fmt);
vsprintf(buf, fmt, ap);
va_end(ap);
return buf;
}
int main(int argc, const char *argv[])
{
char *b;
b = xsprintf("my favorite fruits are: %s, %s, and %s", "coffee", "C", "oranges");
printf("size de buf is %d\n", strlen(b)); //this works. After it, it segfaults.
/*
free(b);
b = NULL;
*/
b = xsprintf("my favorite fruits are: %s, %s, and %s", "coffee", "C", "oranges");
printf("size de buf is %d\n", strlen(b));
printf("%s", b);
return 0;
}
here's the output of this program:
size de buf is 46
[1] 4305 segmentation fault ./xsprintftest
Am I doing something wrong? Shouldn't I have used va_start
multiple times in a single function? Do you have any alternatives? Thanks a lot! :)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您应该使用
vsnprintf
。使用两次。一旦使用NULL
目标/零大小来找出需要分配的缓冲区的长度,然后第二次填充缓冲区。这样,即使所有参数都不是字符串,您的函数也将起作用。正如所写,如果存在任何非字符串参数(
%d
、%x
、%f
等),它将失败。并且计算%
字符的数量并不是获取参数数量的有效方法。您的结果可能太多(如果有编码为%%
的文字%
字符)或太少(如果%*s
还需要参数) code>、%.*d
等宽度/精度说明符)。You should be using
vsnprintf
. Use it twice. Once with aNULL
destination/zero size to find out the length of the buffer you need to allocate, then a second time to fill the buffer. That way your function will work even if all the arguments are not strings.As written, it will fail if there are any non-string arguments (
%d
,%x
,%f
, etc.). And counting the number of%
characters is not a valid way to get the number of arguments. Your result could be too many (if there are literal%
characters encoded as%%
) or too few (if arguments are also needed for%*s
,%.*d
, etc. width/precision specifiers).将
NULL
作为最后一个参数传递给 xsprintf():然后您的
while()
循环将看到 NULL 并正确终止。正如 R.. 在下面的评论和另一个答案中提到的那样,如果存在其他格式参数, xsprintf 函数将失败。您最好使用 vsprintf,如其他答案中所述。
我在这里的目的只是演示哨兵与 va_arg 的使用。
Pass
NULL
as the last arg to xsprintf():Then your
while()
loop will see the NULL and terminate properly.As R.. mentions in the comment below and in another answer, the xsprintf function will fail if there are other format arguments. You are better off using vsprintf as explained in the other answer.
My intent here was simply to demonstrate the use of a sentinel with va_arg.
首先,尝试使用
vsnprintf
。这只是个好主意。但这不是你的问题。您的问题是您调用
va_arg
的次数不能超过参数的次数。它不返回参数的数量。您必须传入一个参数来告诉它有多少个,或者提取格式字符串中特殊标记的数量以计算出必须隐式有多少个。这就是为什么如果你传递的参数太少,
printf
会阻塞你的程序。它只会不断地从堆栈中取出东西。First off, try using
vsnprintf
. It's just a good idea.That's not your problem, though. Your problem is that you can't call
va_arg
more times than there are arguments. It doesn't return the number of arguments. You must either pass in a parameter telling it how many there are, or extract the number of special tokens in the format string to figure out how many there must implicitly be.That's the reason why
printf
can choke your program if you pass it too few arguments; it will just keep pulling things off the stack.问题在于,在没有特定定义结束的情况下访问
va_arg()
列表的代码位中:stdargs.h
设施没有任何内置的-in 方法来确定 va_list() 何时结束 - 您需要通过您提出的约定明确完成该操作。使用哨兵值(如 bstpierre 的答案),或者提供计数。计数可以是提供的显式参数,也可以是隐式参数(例如通过计算格式字符串中格式说明符的数量,如printf()
系列所做的那样)。当然,您还存在一个问题,即您的代码当前仅支持一种格式说明符 (
%s
),但我认为此时这是有意的。The problem is that in the bit of code where you're accessing the
va_arg()
list without a particular defined end:The
stdargs.h
facilities don't have any built-in method for determining when the end of theva_list()
occurs - you need to have that explicitly done by a convention you come up with. Either using a sentinel value (as in bstpierre's answer), or by having a count provided. A count can be an explicit parameter that's provided, or it can be implicit (such as by counting the number of format specifiers in the format string like theprintf()
family does).Of course, you also have the issue that your code currently only supports the one kind of format-specifier (
%s
), but I assumed that that's intentional at this point.非常感谢您的回答和想法!所以我重写了我的函数,如下所示:
它的工作就像一个魅力!感谢一百万次:)
Thanks a lot for your answers and ideas! So I rewrote my function like this:
And it's working like a charm! Thanks a million times :)