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 field
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.
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
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.
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 :)
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);