我的功能大致如此:
typedef struct SomeType {
...
} SomeType;
void TakesArgs(SomeType *t1, ...) {
// iterates through arguments
}
// usage:
TakesArgs(&a, &b, &c);
如果我要将TakesArgs
更改为无操作,同时仍保留所有调用代码,我是否会使用内存(或其他方式)运行任何奇怪的风险?
void TakesArgs(SomeType *t1, ...) {
return;
}
// usage unchanged:
TakesArgs(&a, &b, &c);
换句话说,跳过在原始实现中执行的va_list
/ va_start
舞会有任何奇怪的副作用吗?
答案 0 :(得分:8)
是的,这是非常安全的。您不需要阅读所有可变参数只是为了阅读它们。您甚至不需要在TakesArgs
内启动可变参数读取序列。
通常意味着执行任何参数传递维护任务的负担都赋予调用代码(它们的工作方式通常被认为是"传统的" C调用约定)。被叫者不必做任何事情。
答案 1 :(得分:2)
我认为这是安全的,尽管标准在这一点上并非非常明确。
N1570 7.16第3段说:
如果需要访问不同的参数,则调用函数 应在此声明一个对象(通常称为
ap
子条款)类型va_list
。
请注意该句子的开头:" 如果需要访问不同的参数"。这意味着如果不需要访问不同的参数,则不需要声明va_list
对象 - 这将导致无法调用va_start
,va_arg
,或va_end
。
可能的反驳是va_end
(N1570 7.16.1.3)的描述说:
如果没有相应的
va_start
或va_copy
的调用 宏,或者如果在返回之前未调用va_end
宏,则 行为未定。
但是,根据上下文,我认为如果在调用va_end
之后未调用,则适用。
答案 2 :(得分:1)
[回应评论时编辑。]
有些系统默认情况下弹出参数是被调用者的工作。这显然会让你陷入困境。 但是,正是由于这个原因,必须正确声明可变参数函数,并且声明必须对调用者正确可见。原因是在这些系统上,可变函数必须使用非默认的调用序列,其中调用者弹出参数,因为只有调用者可以确定有多少。所以只要你的函数被正确声明,你就应该是安全的。