【问题标题】:printf a buffer with nullsprintf 带有空值的缓冲区
【发布时间】:2011-08-25 01:56:12
【问题描述】:

打印字符串时是否有一些花哨的 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);
}

【问题讨论】:

  • void main() 是错误的。将其设为 int main() 用于 C++,int main(void) 用于 C。(由于您使用的是 &lt;cstdio&gt;&lt;cstring&gt;,显然您使用的是 C++,所以它应该是 int main()。)
  • 您的示例非常明显地融合了 C 和 C++,这很好,但您可以期待收到各种答案。
  • 确实,我使用了 C++ 和 c 的混合。 C++ 非常适合让事情快速进行。 C 速度很快。由于使用了 printf,我标记了“c”。

标签: c++ c printf packet


【解决方案1】:

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

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

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

3) 遍历每个字符并打印。

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

【讨论】:

  • 遗憾的是答案是否定的。但fwrite(buffer, 1, size, stdout); 适用于 C++。谢谢!
【解决方案2】:

没有办法告诉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 中并打印(如果您不介意重复),因为NULLs 不分隔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

但更好

您可以使用std::ostream 中的write,因为毕竟您使用的是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);

【讨论】:

  • 不应该是string strwithnulls(buf, 7)吗?
  • @John 它可以是任何一个,因为一个重载需要 char* 和一个长度,另一个需要一个开始和结束迭代器。
  • 我梦想有一天人们会在为什么在他们实际点击按钮之前对答案投反对票。毫无意义和无用的投票是没有任何解释的毫无意义和无用的。
【解决方案3】:

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

fwrite(buffer, size, 1, stdout);

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

我没有回应对典型 C++ iostream 的引用,因为我觉得您更喜欢标准 C 中的某些东西。

【讨论】:

    【解决方案4】:

    首先,您的memcpy 操作每个复制六个字节,因为"hello""world" 都是char[6],结果是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, "==&gt; ");

    【讨论】:

    • 首先,您的帖子非常粗鲁。其次,strcpy 既不安全又比 memcpy 慢。第三,这可能是我的错,目的是为了调试目的快速打印一些东西。我已经演示了一个快速修复来获得我想要的东西,你发布的额外代码是不必要的。
    • @Chad: memcpystrcpy 与使用它们的程序员一样不安全。对于memcpy,您需要使用两种尺寸(源尺寸和目标尺寸)中较小的一个。使用strcpy,您需要了解两种尺寸,以确保您没有做坏事。无论哪种方式,您都必须知道这两个函数的源大小和目标大小。
    【解决方案5】:

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

    假设是后者,并借用@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];
            }
        }
    }
    

    如果您使用的是 C 而不是 C++,请替换 cout &lt;&lt; ...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-26
      • 1970-01-01
      • 2021-12-14
      • 2014-11-28
      • 2013-11-19
      • 1970-01-01
      相关资源
      最近更新 更多