printf 带有空值的缓冲区

发布于 2024-12-01 04:44:55 字数 810 浏览 1 评论 0原文

是否有一些奇特的 printf 语法可以在打印字符串时忽略空值?

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

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

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

Is there some fancy printf syntax to ignore nulls when printing a string?

Example use case: printing a network packet that contains a bunch of null terminated strings.

My test code to illustrate the issue:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

云巢 2024-12-08 04:44:55

printf 假定字符串是c 风格的(即以空字符结尾)。您需要执行以下操作之一:

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

2) 使用 write 命令(来自 unistd.h< /code>,C 风格)

3)迭代每个字符并打印。

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

printf assumes strings are c-style (i.e. ending in null characters). You need to do one of the following:

1) use the write method of ostream (C++ style)

2) use the write command (from unistd.h, C style)

3) iterate through each character and print.

When I am debugging packets, oftentimes I will print out each character using the %02hhx format to be sure I see the exact code (without any quirks about printing null characters to the screen)

横笛休吹塞上声 2024-12-08 04:44:55

没有办法告诉 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

可以将缓冲区包装在字符串中并打印它(如果您不介意重复),因为NULL 不会分隔 string

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

There isn't a way to tell printf the length of the string you want to print. You'll need to print each character individually:

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

You could wrap the buffer in a string and print that (if you don't mind the duplication), since NULLs do not delimit strings:

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

But better yet

you could use write of std::ostream, because you are using C++ after all:

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

If you are actually using C (why'd you tag it C++?) you can do this:

char buf[] = {'a', 'b', 'c', 0, 'a', 'b', 'c'};
fwrite(buf, 1, 7, stdout);
与君绝 2024-12-08 04:44:55

没有想到什么,所以为什么不使用 fwrite() 来代替。假设您知道缓冲区内容的格式,则此操作有效。

fwrite(buffer, size, 1, stdout);

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

我没有回应对典型 C++ iostream 的引用,因为我的印象是您更喜欢标准 C 中的某些内容。

There is nothing that comes to mind, so why not use fwrite() instead. This works assuming you know the format of the contents of your buffer.

fwrite(buffer, size, 1, stdout);

If you require further formatted output you can use printf() before and after the call to fwrite().

I am not responding with references to typical C++ iostreams because I got the impression you preferred something in standard C.

无悔心 2024-12-08 04:44:55

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

接下来,“如何打印网络数据包”?我有一个实用函数 hexdump ,它以十六行打印任意内存,也许您会发现它很有用:

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, " ==>“);

First off, your memcpy operations copy six bytes each, since both "hello" and "world" are char[6], and the result is h|e|l|l|o|\0|w|o|r|l|d|\0. That's why you don't copy strings with memcpy, but rather with the cleverly named strcpy.

Next, "how would you print network packets"? I have a utility function hexdump that prints arbitrary memory in lines of sixteen, maybe you'll find it useful:

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

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

一世旳自豪 2024-12-08 04:44:55

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

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

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

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

Do you want to ignore nulls, or print them in some visible form?

Assuming the latter, and borrowing @Seth's code:

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

Replace cout << ... if you're using C rather than C++.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文