【问题标题】:Why it is right for buffer's size is small when using sprintf in C++为什么在 C++ 中使用 sprintf 时缓冲区的大小很小
【发布时间】:2013-11-29 06:15:51
【问题描述】:
#include <cstdio> 
#include <iostream> 

using namespace std;

int main () 
{
      char buffer [1];     
      sprintf (buffer, "%d is one number", 1); 
      cout<<buffer<<endl;

      return 0; 
 }

buffer 的大小只有一个,但cout 可以打印正确的结果。为什么?

这样做安全吗?或者我在使用char *相关方法时必须考虑为缓冲区设置一个大尺寸?

【问题讨论】:

  • 你可以在 C++ 中自爆。您超出了buffer 数组,但显然这并没有在运行时造成严重到足以导致程序运行异常的问题。就cout 而言,buffer 只是一个指向以空字符结尾的字符串的指针。
  • 不对;这是未定义的行为,就是这样:undefined.

标签: c++ string printf


【解决方案1】:

不,这不安全。

C 风格的字符串需要以空值结尾,但buffer 中没有足够的空间。未定义的行为并不意味着保证工作或不工作。当我测试你的程序时,我遇到了分段错误。

【讨论】:

    【解决方案2】:

    正如于浩所说:不安全! 但为什么有时它会起作用?

    char buffer[1]
    

    不是托管数组。它只是给编译器一个提示,他应该为一个字符保留空间。变量缓冲区用作指向该空间的指针,并丢失有关原始大小的所有信息。所以上面的说法和写法一样:

    char bufferVar = '\0'; /* a single character */
    char *buffer = &bufferVar; /* a pointer to bufferVar */
    

    缓冲区只包含一个字符的地址,但根本没有其他信息! 你的 sprintf 期望这样一个地址,一个快乐的从缓冲区开始写入它的字符串。

    分段错误是来自操作系统的消息。您的进程为一个字节分配空间。操作系统以页面(段)的形式管理您的内存。当您越过这些段的边界时,会引发分段错误。 据我所知,这取决于编译器是在段的开头还是结尾分配变量。

    于浩的编译器显然把它们放在最后——你的放在前面。所以你的 sprintf 不会写在段的边界上。

    希望对你有帮助。

    【讨论】:

    • “操作系统以页面(段)的形式管理您的内存。当您越过这些段的边界时,会引发分段错误。”这部分是完全错误的。
    • 它的简化 - 我同意!大错特错? en.wikipedia.org/wiki/Segmentation_fault
    • 根据那个网页,如果它仍然是 1970 年代,那你就对了。 Segmentation fault 原来确实是指现在所谓的page fault,但今天的意思完全不同了。
    • 页面错误是不同的! “分段”是当今称为分页的内存管理方法的历史术语(参见例如 Lions' Commentary on UNIX 6th Edition, with Source Code),但该术语仍用于“分段错误”错误的上下文中;页面错误有不同的含义(尽管页面错误可能导致分段错误)。
    • “操作系统以页面(段)的形式管理您的内存。当您越过这些段的边界时,会引发分段错误。”这就是你说的。您指的是页面错误。
    【解决方案3】:

    至于存储char * 字符串所需的大小,许多C stdlib 字符串函数会告诉您如果您将它们传递给NULL,它们需要的长度。您可以在为字符串分配存储空间之前调用它以了解您需要多少存储空间:

    std::cout << "You need a buffer that can store "
              << sprintf (NULL, "%d is one number", 1) + 1
              << " characters to safely store your string."
              << std::endl;
    

    另一种解决方案是使用snprintf (...) 之类的东西,它可以保证它会截断输出,以免超出缓冲区:

     snprintf (buffer, 1, "%d is one number", 1);
                   // ~~~
                   // Length of buffer
    

    在您的情况下,缓冲区只有 1 个字符长,因此它只有足够的空间来存储空终止符;不是特别有用。

    【讨论】:

      猜你喜欢
      • 2011-04-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-24
      • 2021-12-06
      • 1970-01-01
      • 2011-11-26
      • 2017-04-07
      相关资源
      最近更新 更多