【问题标题】:C++ non null terminated char array outputtingC ++非空终止字符数组输出
【发布时间】:2009-10-09 07:31:30
【问题描述】:

我试图将一个非空终止的字符数组输出到文件中。

实际上,我正在接收数据包,然后打印它们的字段。

现在,由于这些字段不是以空值结尾的,例如,一个大小为 512 的数据段可能会被完全占用,也可能不会被完全占用。

当我将这些数据写入文件时,我使用的是简单的

那么,我怎样才能告诉输出函数只写这么多特定字节数

而不是使用这样的每次调用都很昂贵的东西:

enter code here  

bytescopied = strncpy(dest, src, maxbytes);

if (bytescopied < 0) { // indicates no bytes copied, parameter error

    throw(fit);          // error handler stuff here

 } else if (bytescopied == maxbytes) {

    dest[maxbytes-1] = '\0';   // force null terminator

}

【问题讨论】:

    标签: c++ string file-io


    【解决方案1】:

    如果你想准确输入maxbytes 字节,请使用write 方法

    stream.write(buffer, maxbytes);
    

    如果缓冲区中可以有更少的字节,你怎么知道你的缓冲区包含多少字节?如果'\0'标记缓冲区结束,你可以写:

    stream.write(buffer, std::find(buffer, buffer+maxbytes, '\0') - buffer);
    

    【讨论】:

    • 在您的第二次调用中,整个第二个参数只是调用普通旧strlen 的一种迂回方式。但在这种情况下,您不妨对整个语句使用更惯用的方式:stream &lt;&lt; buffer
    • 没有。 strlen 在 maxbytes 之后不会停止。
    • strnlen 将。 strnlen 调用看起来会更干净:strnlen(buffer, maxbytes)。不要乱用指针或任何东西
    • strnlen 有一个缺点 - 它不是标准的。
    【解决方案2】:

    一个便宜的解决方案是有一个缓冲区,它有空间容纳一个额外的空字符,当你知道实际大小时,只需在该点放置一个空字符,然后像你已经做的那样输出以空字符结尾的缓冲区。快速可靠。

    【讨论】:

    • 是的,您可以将多余的字符保存到临时变量中。打印完成后,只需将其恢复即可。
    【解决方案3】:

    这可行,但不能安全地避免意外调用标准的char* 版本的operator&lt;&lt;

    #include <iostream>
    
    template <unsigned N>
    std::ostream& operator<< ( std::ostream& out, const char ( & data ) [N] )
    {
        out.write ( data, N ); 
        // or out.write ( data, strnlen ( data, N ) ); 
        // if you want to stop at a '\0' in the data
        return out;
    }
    
    
    struct Foo {
        char   one[5];
        char   two[1];
        char   three[5];
    };
    
    int main ( void )
    {
        using namespace std;
    
        Foo foo = {
            { 'h', 'e', 'l', 'l', 'o' }, 
            { ' ' }, 
            {'w', 'o', 'r', 'l', 'd'} };
    
        cout << foo.one;
        cout << foo.two;
        cout << foo.three;
        cout << endl;
    }
    

    这样更安全,使用限制下一个char* 输出长度的maxw 类型:

    struct maxw {
        unsigned n;
        maxw ( unsigned n ) : n ( n ) { }
    };
    
    struct maxw_stream {
        std::ostream& stream;
        unsigned n;
        maxw_stream ( std::ostream& stream, unsigned n ) :
                stream ( stream ),
                n ( n ) {
        }
    };
    
    maxw_stream operator<< ( std::ostream& out, const maxw& m )
    {
        return maxw_stream ( out, m.n );
    }
    
    std::ostream& operator<< ( const maxw_stream& out, const char* data )
    {
        out.stream.write ( data, strnlen ( data, out.n ) );
        return out.stream;
    }
    
    // eg:
    cout << maxw(4) << "Hello World!"  << endl;
    // Hell\n
    cout << maxw(100) << "Hello World!" << endl;
    // Hello World!\n
    

    【讨论】:

    • strnlen 的问题在于 AFAIK 它不是标准的。而且您的模板函数很好,但是如果将缓冲区作为普通指针而不是数组传递,则不会出现警告,只会调用标准的 c-string 输出函数。
    • C99 已经十年了,IIRC C++0x 将引入所有 C99 标准。
    • 嗯,我搜索了open-std.org/JTC1/SC22/wg14/www/docs/n1124.pdf,找不到strnlen。
    【解决方案4】:

    我主要看到两种解决方案。

    如果是 ASCII 数据:

    memset(dest,0,destlength); 
    bytescopied = strncpy(dest, src, maxbytes);
    

    那么您将始终在缓冲区中有明确的以空字符结尾的字符串。

    在ASCII数据的情况下第二个:

    std::string yourASCII(src,maxbytes);
    yourASCII.c_str() // would be null terminated.
    

    【讨论】:

      【解决方案5】:

      如果你不关心最后一个字节,你可以直接

      buffer[buffersize-1] = 0;
      

      然后将缓冲区提供给您想要的任何字符串函数。如果它更短,则所有内容都会运行到已经存在的空终止符,如果没有终止符,它将运行到您刚刚创建的那个。

      而且速度很快:)

      【讨论】:

        猜你喜欢
        • 2013-10-22
        • 2013-08-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多