7

I was trying to output a not null terminated char array to a file.

Actual thing is, I am receiving packets and then printing their fields.

Now as these fields are not null terminated, for example, a data segment which has size of 512 but may or may not be completely occupied.

When I write this data to a file I am using simple << overloaded function which does not know any thing about actual data and only looks for termination of data segment.

So, how can I tell the output function to write only this much specific number of bytes?

Instead of using something like this which is expensive to call each time:

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

}
Graeme Perrow
  • 56,086
  • 21
  • 82
  • 121
changed
  • 2,103
  • 8
  • 36
  • 56

5 Answers5

17

If you want to put exactly maxbytes bytes, use write method

stream.write(buffer, maxbytes);

If you can have less bytes in buffer, how do you know how many of them your buffer contains? If '\0' marks buffer end, you can write:

stream.write(buffer, std::find(buffer, buffer+maxbytes, '\0') - buffer);
Tadeusz Kopec for Ukraine
  • 12,283
  • 6
  • 56
  • 83
3

A cheap solution would be to have a buffer that has space for an extra null character and just put a null character at the point when you know the actual size and then output the null-terminated buffer as you already do. Fast and reliable.

sharptooth
  • 167,383
  • 100
  • 513
  • 979
3

This works, but isn't safe against accidentally calling the standard char* version of operator<<:

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

This is safer, using a maxw type which limits the length of the next char* output:

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
Pete Kirkham
  • 48,893
  • 5
  • 92
  • 171
0

I see mainly two solutions.

In case of ASCII data:

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

then You'll always have clear null-terminated string in buffor.

Second in case of ASCII data:

std::string yourASCII(src,maxbytes);
yourASCII.c_str() // would be null terminated.
bua
  • 4,761
  • 1
  • 26
  • 32
0

If you don't care about the last byte, you can just

buffer[buffersize-1] = 0;

and then feed buffer to whatever string function you want. If it is shorter, everything will run to the null terminator that already exists, and if there was no terminator it will run to the one you just created.

And it's fast :)

Combuster
  • 583
  • 5
  • 19