Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/159.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;任何参数的函数都会导致分段错误_C++_Parameters_Segmentation Fault_Variadic Functions - Fatal编程技术网

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);