我有一个函数对sscanf()
进行一系列调用,然后在每个函数之后更新字符串指针以指向sscanf()
未使用的第一个字符,如下所示:
if(sscanf(str, "%d%n", &fooInt, &length) != 1)
{
// error handling
}
str+=length;
为了清理它并避免重复这几次,我想把它封装成一个很好的实用函数,看起来如下所示:
int newSscanf ( char ** str, const char * format, ...)
{
int rv;
int length;
char buf[MAX_LENGTH];
va_list args;
strcpy(buf, format);
strcat(buf, "%n");
va_start(args, format);
rv = vsscanf(*str, buf, args, &length); //Not valid but this is the spirit
va_end(args);
*str += length;
return rv;
}
然后我可以简化下面的调用以删除附加参数/簿记:
if(newSscanf(&str, "%d", &fooInt) != 1)
{
// error handling
}
不幸的是,我找不到将&length
参数直接附加到arg列表末尾或newSscanf()
内的方法。有没有办法解决这个问题,还是我在每次通话时手动处理簿记?
答案 0 :(得分:3)
你是对的 - 你不能将额外的参数填入va_list
。你能做的最好的可能就是这样的一些宏观技巧:
int _newSscanf ( char ** str, int *length, const char * format, ...)
{
int rv;
va_list args;
va_start(args, format);
rv = vsscanf(*str, format, args);
va_end(args);
*str += *length;
return rv;
}
#define NEW_SSCANF_INIT int _ss_len
#define newSscanf(str, fmt, ...) _newSscanf(str, &_ss_len, fmt "%n", __VA_ARGS__, &_ss_len)
...并要求来电者:
NEW_SSCANF_INIT;
if (newSscanf(&str, "%d", &fooInt) != 1)
{
// error handling
}
如果您可以使用GCC扩展,则可以使用“语句表达式”取消NEW_SSCANF_INIT
部分,使其更清晰:
#define newSscanf(str, fmt, ...) ({int _ss_len; _newSscanf(str, &_ss_len, fmt "%n", __VA_ARGS__, &_ss_len);})
答案 1 :(得分:1)
如果没有弄清楚可变参数列表是如何工作的(并因此使代码不可移植),则无法修改参数。
但我确实有一个想法可能会或可能不会奏效。我没有测试过,因为我真的不认为你应该使用它,但是,如果你真的很想做到这一点,它可能有所帮助。
由于您只想获得扫描的字符数,您应该意识到不必须与调用者变量的实际设置同时进行。
让您的代码扫描字符串以根据调用者的需要设置参数。根本不需要改变。
下一阶段是稍微棘手的一个。
计算格式字符串中%
字符的数量,这些字符不会紧跟%
或*
- 换句话说,需要提供的变量数量sscanf
。如果这大于上限,则断言(参见下面的代码)。
然后在格式字符串的末尾添加%n
个序列,以确保您获得字符数。
然后,使用新的格式字符串,使用垃圾缓冲区(重复)从扫描中接收所有值,包括最后一个(字符数)。
这样的事情(调试的责任在于你):
typedef union {
char junk[512]; // Be *very* careful with "%s" buffer overflows.
int length;
} tJunkbuff;
int newSscanf (char **str, const char *format, ...) {
int rv, length;
char buf[MAX_LENGTH];
tJunkBuff junkbuff;
va_list args;
// Populate variables.
va_start (args, format);
rv = vsscanf (*str, buf, args);
va_end (args);
// Get length.
// String scanning for % count and assert/error left out.
// Only 20 allowed (depends on number of jb.junk variables below (n-1)).
strcpy (buf, format);
strcat (buf, "%n");
sscanf (*str, buf,
jb.junk,jb.junk, jb.junk, jb.junk, jb.junk,
jb.junk,jb.junk, jb.junk, jb.junk, jb.junk,
jb.junk,jb.junk, jb.junk, jb.junk, jb.junk,
jb.junk,jb.junk, jb.junk, jb.junk, jb.junk,
jb.junk); // May need to be "&(jb.junk)" ?
*str += jb.length;
return rv;
}
如果您决定试一试,我会对您的听力感兴趣。那是我的工作(和责任)完成的。我很高兴卖给你电锯但是,如果你在使用它的时候剪掉你的腿,这就是你的问题: - )
答案 2 :(得分:0)
您正在错误地调用该函数,请查看char **str
的参数,其中包含一个call-by-reference参数:
if(newSscanf(&str, "%d", &fooInt) != 1) { // error handling }