输出一个带有空值的缓冲区

printf a buffer with nulls

本文关键字:空值 缓冲区 一个 输出      更新时间:2023-10-16

是否有一些花哨的printf语法在打印字符串时忽略null ?

示例用例:打印一个包含一堆以空结束的字符串的网络数据包。

我用来说明这个问题的测试代码:

#include <cstdio>
#include <cstring>
void main()
{
    char buffer[32];
    const char h[] = "hello";
    const char w[] = "world";
    const int size = sizeof(w) + sizeof(h);
    memcpy(buffer, h, sizeof(h));
    memcpy(buffer + sizeof(h), w, sizeof(w));
    //try printing stuff with printf
    printf("prints only 'hello' [%s]n",buffer);
    printf("this prints '<bunch of spaces> hello' [%*s]n",size,buffer);
    printf("and this prints 'hello' [%.*s]n",size,buffer);
    //hack fixup code
    for(int i = 0; i < size; ++i)
    {
        if(buffer[i] == 0)
            buffer[i] = ' ';
    }
    printf("this prints 'hello world ' [%.*s]n",size,buffer);
}

printf假定字符串为c样式(即以空字符结尾)。您需要执行以下操作之一:

1)使用ostream的write方法(c++风格)

2)使用write命令(来自unistd.h, C样式)

3)遍历每个字符并输出

当我调试数据包时,通常我会使用%02hhx格式打印出每个字符,以确保我看到确切的代码(没有任何关于将空字符打印到屏幕上的怪癖)

没有办法告诉printf要打印的字符串的长度。您需要单独打印每个字符:

void printbuf(const char* buffer, int len) {
    for (int i = 0; i < len; ++i)
        printf("%c", buffer[i]);
}
char buf[] = {'a', 'b', 'c', 0, 'a', 'b', 'c'};
printbuf(buf, 7);
// prints
// abc abc

可以将缓冲区包裹在string中并打印出来(如果您不介意重复的话),因为NULL s不分隔string s:

char buf[] = {'a', 'b', 'c', 0, 'a', 'b', 'c'};
string strwithnulls(buf, buf + 7); // or as John pointed out, string strwithnulls(buf, 7);
cout << strwithnulls;
// prints
// abc abc

但更好的是

你可以使用std::ostreamwrite,因为你毕竟在使用c++:

char buf[] = {'a', 'b', 'c', 0, 'a', 'b', 'c'};
cout.write(buf, 7); // best yet

如果你实际使用的是C(为什么你标记它c++ ?),你可以这样做:

char buf[] = {'a', 'b', 'c', 0, 'a', 'b', 'c'};
fwrite(buf, 1, 7, stdout);

没有想到什么,那么为什么不使用fwrite()呢?如果您知道缓冲区内容的格式,则此操作可以正常工作。

fwrite(buffer, size, 1, stdout);

如果需要进一步格式化输出,可以在调用fwrite()之前和之后使用printf()。

我没有引用典型的c++ iostreams,因为我得到的印象是你更喜欢标准C中的东西。

首先,您的memcpy操作各复制6个字节,因为"hello""world"都是char[6],结果是h|e|l|l|o||w|o|r|l|d|。这就是为什么不使用memcpy复制字符串,而是使用巧妙命名的strcpy

下一个,"你将如何打印网络数据包"?我有一个实用函数hexdump,它以16行为单位打印任意内存,也许你会发现它很有用:

void asciiprint(FILE * out, unsigned char c)
{
  if (c < 32 || c > 126) fprintf(out, ".");
  else fprintf(out, "%c", c);
}
void hexdump(FILE * out, const unsigned char * buf, size_t length, const char * delim)
{
  for (size_t k = 0; 16*k < length; k++)
  {
    fprintf(out, "%s", delim);
    for (int i = 0; i < 16 && 16*k + i < length; ++i)
      fprintf(out, "0x%02X ", buf[16*k + i]);
    if (16*(k+1) > length)
      for (size_t i = 0; i < 16*(k+1)-length; ++i)
        fprintf(out, "     ");
    fprintf(out, "    ");
    for (size_t i = 0; i < 16 && 16*k + i < length; ++i)
      asciiprint(out, buf[16*k + i]);
    fprintf(out, "n");
  }
}

用法:hexdump(stdout, (const unsigned char*)buffer, 32, "==> ");

您想忽略空值,还是以某种可见的形式打印它们?

假设是后者,并借用@Seth的代码:

void printbuf(const char* buffer, int len) {
    for (int i = 0; i < len; ++i)
        if (buffer[i] == '') {
             cout << "\0";
        }
        else
            cout << buffer[i];
        }
    }
}

如果您使用的是C而不是c++,请替换cout << ...