va_list 传递给使用 va_arg 的函数无效
va_list passed to a function using va_arg is not working
我有这段使用可变参数函数的代码:
#include <cstdarg>
#include <iostream>
template <typename T>
void bar(va_list vl) {
std::cout << va_arg(vl, T) << std::endl;
}
void foo(int n, ...) {
va_list vl;
va_start(vl, n);
while (n--) {
bar<int>(vl);
}
va_end(vl);
}
int main() {
foo(3, 1, 2, 3);
return 0;
}
不幸的是,这段代码的输出依赖于平台。在 GCC 7 中,我得到:
1
2
3
而在 MSVC 2015 中是
1
1
1
我正在尝试编写代码来获取 GCC 输出,但我想我做错了什么,我不知道在哪里。如果有的话,哪个是正确的输出?
两个编译器都设置为最高警告级别,但它们没有打印任何警告。
在 MSVC 中,作为 va_list
char*
的别名,输出是有意义的。在 GCC 中,它是一个 builtin type,我不知道那里发生了什么。
编辑:
如果我将 bar
的定义更改为 void bar(va_list& vl)
,则输出是相同的。通过引用传递 va_list
是否合法?
您的程序调用了未定义的行为。
semantics of C standard library in C++ is the same as in C and the content of cstdarg should be the same as stdarg.h
in C. C++ standard is big, so I'll use C standard here, which is easier for me to read. From C99 7.15.3,注释我的:
.... The object ap [of type va_list, my annotation] may be passed as an argument to another function; if that function invokes the va_arg macro with parameter ap, the value of ap in the calling function is indeterminate and shall be passed to the va_end macro prior to any further reference to ap.
如果您将 va_list
对象传递给另一个函数并在该函数中调用 va_arg
,则必须在同一函数中调用 va_end
。
根据footnote 221 from C99你可以传递一个指向va_list
的指针。
您应该使用现代 C++11 方法。使用老式的 C 可变参数函数是危险的。
您可以使用 C++ 模板参数包,但在您的情况下简单 std::initializer_list 就可以完成工作并且非常方便:
void foo(std::initializer_list<int> items) {
for (auto item : items) {
std::cout << item << std::endl;
}
}
int main() {
foo({1, 2, 3});
return 0;
}
我有这段使用可变参数函数的代码:
#include <cstdarg>
#include <iostream>
template <typename T>
void bar(va_list vl) {
std::cout << va_arg(vl, T) << std::endl;
}
void foo(int n, ...) {
va_list vl;
va_start(vl, n);
while (n--) {
bar<int>(vl);
}
va_end(vl);
}
int main() {
foo(3, 1, 2, 3);
return 0;
}
不幸的是,这段代码的输出依赖于平台。在 GCC 7 中,我得到:
1
2
3
而在 MSVC 2015 中是
1
1
1
我正在尝试编写代码来获取 GCC 输出,但我想我做错了什么,我不知道在哪里。如果有的话,哪个是正确的输出?
两个编译器都设置为最高警告级别,但它们没有打印任何警告。
在 MSVC 中,作为 va_list
char*
的别名,输出是有意义的。在 GCC 中,它是一个 builtin type,我不知道那里发生了什么。
编辑:
如果我将 bar
的定义更改为 void bar(va_list& vl)
,则输出是相同的。通过引用传递 va_list
是否合法?
您的程序调用了未定义的行为。
semantics of C standard library in C++ is the same as in C and the content of cstdarg should be the same as stdarg.h
in C. C++ standard is big, so I'll use C standard here, which is easier for me to read. From C99 7.15.3,注释我的:
.... The object ap [of type va_list, my annotation] may be passed as an argument to another function; if that function invokes the va_arg macro with parameter ap, the value of ap in the calling function is indeterminate and shall be passed to the va_end macro prior to any further reference to ap.
如果您将 va_list
对象传递给另一个函数并在该函数中调用 va_arg
,则必须在同一函数中调用 va_end
。
根据footnote 221 from C99你可以传递一个指向va_list
的指针。
您应该使用现代 C++11 方法。使用老式的 C 可变参数函数是危险的。
您可以使用 C++ 模板参数包,但在您的情况下简单 std::initializer_list 就可以完成工作并且非常方便:
void foo(std::initializer_list<int> items) {
for (auto item : items) {
std::cout << item << std::endl;
}
}
int main() {
foo({1, 2, 3});
return 0;
}