C++ C++;任何参数的函数都会导致分段错误
这是我的节目,有人知道为什么吗C++ C++;任何参数的函数都会导致分段错误,c++,parameters,segmentation-fault,variadic-functions,C++,Parameters,Segmentation Fault,Variadic Functions,这是我的节目,有人知道为什么吗 #include <iostream> #include <string> #include <stdarg.h> using namespace std; void say(char* name ...) { cout << "Hello, "; cout << name ; va_list ap; va_start(ap,name); for(;;){
#include <iostream>
#include <string>
#include <stdarg.h>
using namespace std;
void say(char* name ...)
{
cout << "Hello, ";
cout << name ;
va_list ap;
va_start(ap,name);
for(;;){
char* str = va_arg(ap, char*);
if (str == 0) break;
cout << ", " << str;
}
cout << endl;
va_end(ap);
}
int main()
{
char *a = "atom";
char *b = "johhny";
char *c = "jim";
say(a,b,c);
}
以下是调试信息:
24 cout << "Hello, ";
(gdb) n
25 cout << name ;
(gdb) n
27 va_start(ap,name);
(gdb) n
30 char* str = va_arg(ap, char*);
(gdb) n
31 if (str == 0) break;
(gdb) n
32 cout << ", " << str;
(gdb) n
29 for(;;){
(gdb) n
30 char* str = va_arg(ap, char*);
(gdb) n
31 if (str == 0) break;
(gdb) n
32 cout << ", " << str;
(gdb) n
29 for(;;){
(gdb) n
30 char* str = va_arg(ap, char*);
(gdb) n
31 if (str == 0) break;
(gdb) n
32 cout << ", " << str;
(gdb) n
Program received signal SIGSEGV, Segmentation fault.
0x0000003f0b06fed0 in strlen () from /lib64/tls/libc.so.6
(gdb) n
Single stepping until exit from function strlen,
which has no line number information.
Program terminated with signal SIGSEGV, Segmentation fault.
The program no longer exists.
24 cout您的代码依赖于看到NULL
,但调用者不提供它
va_arg
不知道参数列表何时结束。当您的代码执行此操作时
if (str == 0) break;
这是第四次,它检索一些超过vararg列表末尾的垃圾,并尝试取消对它的引用。这就是导致未定义行为的原因,这将导致崩溃
显式传递它可以修复问题():
调用va_arg
的次数超过实际参数数是未定义的行为。您没有任何自动的方法来检测输出的结束。您必须自己跟踪有效参数的数量。有多种方法可以做到这一点,例如:
- 您可以将null或任何特殊值传递给signal end
- 可以将参数数作为单独的强制参数传递
- 您可以维护某种格式字符串,如
printf
或scanf
如果(str==0)中断代码>-这在实践中起什么作用?下次在调试器中单步执行某些代码时,如果您知道崩溃将在何时何地发生,请务必查看所涉及的变量。如果你能使用C++11,看看可变模板。它可以以更高的安全性实现完全相同的功能(您可以传递编译时已知的不同类型,编译时已知的参数数量,…)在传递时展开(char*)0
以结束参数列表:使用nullptr
将nullptr\t
对象放在堆栈上。虽然它可以用来与任何其他指针进行比较,但它本身并不是一个指针,并且与va_arg(ap,char*)
宏调用不兼容。谢谢@JoachimPileborg:我已经删除了我的答案。@Bathsheba Me to,不过我会保留评论,以供将来的访问者参考。
if (str == 0) break;
say(a,b,c, (char*)0);