【问题标题】:how to not null terminate a buffer?如何不为空终止缓冲区?
【发布时间】:2021-01-26 19:10:27
【问题描述】:

基本上我想知道是否有办法在缓冲区中保留空字节?

例子:

#include <stdio.h>

int main()
{
    char buf[] = "hello there\x00, Hi";
    printf("%s\n", buf);

    return 0;
}

不幸的是,如果您在上面进行编译,您将得到的输出仅为hello there(由\x00 终止的null)。那么有没有办法将空字节保留在堆栈中并在此之后也获得Hi

仅供参考,如果你想建议用\\x00 转义\,我不能这样做。

【问题讨论】:

  • 如果您将其视为字符串,则在字节数组中嵌入 0 会很棘手。你能解释一下你为什么想要这个吗?听起来你实际上想要别的东西。
  • 由于%s 在第一个空字节处停止处理,因此无法通过对printf() 的简单(单个)调用来完成。你想要输出什么?您也可以使用fwrite(buff, sizeof(buff) - 1, 1, stdout); 写入空字节(后跟putchar('\n'); 输出换行符)。
  • “,嗨”也在堆栈中(在buf 中)。它只是没有打印出来。 C 风格的字符串不能包含 '\0',因为这是它用来确定字符串结尾的标记值。

标签: c substring c-strings


【解决方案1】:

根据定义,C 字符串不能包含 NUL 字节,它被明确保留为终止字符。如果您需要一个支持它的原始缓冲区,那么您不能使用 C 字符串。你需要区别对待。所有以str 开头的 C 字符串函数都在这里禁止使用。

printf%s 当然会在 NUL 字节处终止。如果要打印整个缓冲区,则需要使用较低级别的工具,例如 fwrite

【讨论】:

    【解决方案2】:

    当你说

    char buf[] = "hello there\x00, Hi";
    

    空字节和它们后面的“Hi”肯定“在里面”。问题仅仅是printf 不打印它们,因为printf 在看到第一个空字节时总是停止。大多数其他标准字符串处理函数也会有同样的问题。

    如果需要,您可以使用包含空字节的字符串,但如果不是在第一个空字节处,您将必须找出自己的方法来跟踪字符串的长度或结束的位置。

    处理可能包含空字节的文本“字符串”的常用方法是使用第二个单独的字符计数变量。 (例如,这就是标准 fwrite 函数的工作方式。)或者(尽管相当不标准),我编写了检测并跳过嵌入的空字节的代码,并确定它只是 really 在当它找到一对背靠背的空字节时,字符串的结尾。

    而且,不,你是对的,没有办法“逃避”空字节。解释为什么没有办法,以及为什么不可能有可能是有启发性的。 “幕后”,可以这么说,“空字节”只是一个值为 0 的字节。这是所有标准 C 字符串处理函数都在寻找来确定字符串结尾的东西,没有办法告诉他们中的任何一个使用其他解释,以某种方式忽略假设的“转义”空字节,只停在“真实”空字节处。就 C 字符串终止而言,空字节是空字节是空字节。

    事实上,当你写"\0""\x00" 时,你已经在逃避事情了。如果你写"0",你会得到一个长度为1的字符串,其中包含字符'0'(十六进制0x30),如果你写"x00",你会得到一个长度为3的字符串,其中包含x 0 0。只有反斜杠将这些字符串中的任何一个转换为包含文字空字符的字符串。如果您尝试“转义”空字符,可能通过编写"\\0""\\x00",会发生什么情况是您转义了反斜杠,这将带走它的特殊含义,这意味着它无济于事创建一个真正的空字符,而您最终会得到一个包含两个字符 \ 0 或四个字符 \ x 0 0 的字符串。

    【讨论】:

      【解决方案3】:

      如果您知道嵌入零字符的字符串的实际大小,或者您知道由存储在缓冲区中的零字符分隔的子字符串的数量,那么您可以将其分段输出。

      例如

      #include <stdio.h>
      #include <string.h>
      
      int main( void )
      {
          char buf[] = "hello there\x00, Hi";
          printf("%s", buf);
      
          size_t n = strlen( buf );
          
          if ( n < sizeof( buf ) - 1 ) puts( buf + n + 1 ); 
          
          return 0;
      }
      

      程序输出是

      hello there, Hi
      

      【讨论】:

      • 这似乎是一个巨大的 hack,当且仅当它只有一个 NUL 字节时才有效。
      • @tadman 没有破解。知道嵌入零个字符或多个子字符串的整个字符串的总长度就足够了。
      • 如果它周围有一个循环,那么它会一直运行直到整个缓冲区都被写入我至少能够看到它是如何技术上是一个有效的解决方案,但就目前而言,它在任何情况下都无法使用 > 1 NUL 字节。
      • @tadman 正如我所写,必要条件是您知道整个字符串的总长度或存储在缓冲区中的子字符串的数量。缓冲区包含多个字符串的情况并不少见。
      • ...或者你可以使用fwrite
      猜你喜欢
      • 2015-02-27
      • 1970-01-01
      • 2020-11-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-19
      • 2011-01-11
      • 1970-01-01
      相关资源
      最近更新 更多