Click to See Complete Forum and Search --> : [RESOLVED] question about memcpy, char* and string


lab1
June 23rd, 2008, 02:28 PM
Hello,

I have the following code that works fine for packing and unpacking with memcpy:

#include <string>
using namespace std;

int main()
{
// PACK
char *bufptr;
char buf[12];
unsigned int data1 = 1003;
unsigned int data2 = 0;
float data3 = 90.0;
bufptr = buf;
memcpy(bufptr, &data1, 4);
bufptr+=4;
memcpy(bufptr, &data2, 4);
bufptr+=4;
memcpy(bufptr, &data3, 4);
bufptr+=4;

// UNPACK
unsigned int _data1, _data2;
float _data3;
char *temp = buf;
memcpy(&_data1, temp, 4);
temp+=4;
memcpy(&_data2, temp, 4);
temp+=4;
memcpy(&_data3, temp, 4);
temp+=4;
return 0;
}


but now I tried to add strings into the mix, and it stops working. What am I doing wrong with the strings here?

#include <string>
using namespace std;

int main()
{
// PACK
char *bufptr;
char buf[12];
unsigned int data1 = 1003;
unsigned int data2 = 0;
float data3 = 90.0;
bufptr = buf;
memcpy(bufptr, &data1, 4);
bufptr+=4;
memcpy(bufptr, &data2, 4);
bufptr+=4;
memcpy(bufptr, &data3, 4);
bufptr+=4;
string message=buf;

// UNPACK
unsigned int _data1, _data2;
float _data3;
char *temp = (char*)message.c_str();
memcpy(&_data1, temp, 4);
temp+=4;
memcpy(&_data2, temp, 4);
temp+=4;
memcpy(&_data3, temp, 4);
temp+=4;
return 0;
}


I am guessing trhe line that is wrong is this line:

char *temp = (char*)message.c_str();

Can anyone help me to make this work correctly with strings?

Thanks!!

VladimirF
June 23rd, 2008, 02:46 PM
Can anyone help me to make this work correctly with strings?You could probably make it work. But it is a bad idea to keep binary data in strings because all internal functions that need to determine its size will look for a first 0 byte...

a1ex07
June 23rd, 2008, 02:47 PM
There is nothing wrong with char *temp = (char*)message.c_str();
All 'magic' happens here string message=buf;
You initialize string object with c-string (which is 0-terminated string), so as soon as the first 0 occurs in buf, the process is stopped. I'd suggest that vector<char> is more natural type in this case.

lab1
June 23rd, 2008, 02:55 PM
Hey Alex,

How can I fix this then? How do I copy a char buffer into a string?

Thanks!

lab1
June 23rd, 2008, 03:01 PM
Hey Alex,

What if I must use a string? is there any possible way to initial a string with a char buffer?

Thanks!
Curtis

GCDEF
June 23rd, 2008, 03:01 PM
Hey Alex,

How can I fix this then? How do I copy a char buffer into a string?

Thanks!

As has been pointed out, a string is not the right data type if your data contains embedded nulls.

lab1
June 23rd, 2008, 03:07 PM
Sorry but I think you are wrong. Here is some example code:

char buffer[14] = "testtest0test";
char buffer2[14];
string message=buffer;
char *temp = (char*)message.c_str();
memcpy(&buffer2, temp, 14);


or is this "0" not an embedded null?

Thanks

Paul McKenzie
June 23rd, 2008, 03:10 PM
Hey Alex,

What if I must use a string? is there any possible way to initial a string with a char buffer?Have you tried looking at all of the constructors that string takes?

http://www.sgi.com/tech/stl/basic_string.html


#include <string>

int main()
{
std::string s("abc123", 4);
}

In other words, a string buffer as the first parameter, and the number of bytes to use from the buffer is the second parameter.

Regards,

Paul McKenzie

GCDEF
June 23rd, 2008, 03:11 PM
Sorry but I think you are wrong. Here is some example code:

char buffer[14] = "testtest0test";
char buffer2[14];
string message=buffer;
char *temp = (char*)message.c_str();
memcpy(&buffer2, temp, 14);


or is this "0" not an embedded null?

Thanks
No, it's not a null.

a1ex07
June 23rd, 2008, 03:12 PM
You can use vector<char> instead of string

#include <vector>
int main()
{
// PACK
char buf[12];
unsigned int data1 = 1003;
unsigned int data2 = 0;
float data3 = 90.0;
bufptr = buf;
memcpy(bufptr, &data1, 4);
bufptr+=4;
memcpy(bufptr, &data2, 4);
bufptr+=4;
memcpy(bufptr, &data3, 4);
bufptr+=4;
//string message=buf;

std::vector<char> message1(12);
memcpy(&message1[0],buf,12);

// UNPACK
unsigned int _data1, _data2;
float _data3;
//char *temp = (char*)message.c_str();
char *temp = &message1[0];

memcpy(&_data1, temp, 4);
temp+=4;
memcpy(&_data2, temp, 4);
temp+=4;
memcpy(&_data3, temp, 4);
temp+=4;
return 0;
// UNPACK

You can also get rid of all char* variables and change it to :



vector<char> buffer(12);
unsigned int data1 = 1003;
unsigned int data2 = 0;
float data3 = 90.0;
// Pack
memcpy(&buffer[0], &data1, 4);
memcpy(&buffer[4], &data2, 4);
memcpy(&buffer[8], &data3, 4);

// Unpack
memcpy(&_data1, &buffer[0], 4);
memcpy(&_data2, &buffer[4], 4);
memcpy(&_data3, &buffer[8], 4);

Paul McKenzie
June 23rd, 2008, 03:14 PM
As has been pointed out, a string is not the right data type if your data contains embedded nulls.It can be the right data type, if you use the correct functions.

For example, std::string::append(), the correct constructor (which is not what lab1 was using), etc.

If you wish to change the data in place, then a better choice would be vector<char> (but that is also bound to change, since the standards committee has just specified that the contents of std::string are changeable and contiguous, exactly like an array).

Regards,

Paul McKenzie

a1ex07
June 23rd, 2008, 03:27 PM
If you have to stick to string, you can do

//...
string message;
message.resize(12);
for (int i = 0; i<12; i++)
{
message[i] = *(buf+i);
}

I'm not sure how safe it is though...

Paul McKenzie
June 23rd, 2008, 03:34 PM
If you have to stick to string, you can do

//...
string message;
message.resize(12);
for (int i = 0; i<12; i++)
{
message[i] = *(buf+i);
}

You don't need that at all. Did you read my previous message?

string message(buf, 12);

That's all you need to do.

Regards,

Paul McKenzie

MrViggy
June 23rd, 2008, 05:26 PM
There is nothing wrong with char *temp = (char*)message.c_str();
memcpy(&_data1, temp, 4);
temp+=4;
memcpy(&_data2, temp, 4);
temp+=4;
memcpy(&_data3, temp, 4);
temp+=4;

I'm sorry, but this is incorrect! 'c_str()' returns a const char *, casting away the const and modifying the buffer is undefined behavior.

Viggy

a1ex07
June 23rd, 2008, 06:20 PM
I'm sorry, but this is incorrect! 'c_str()' returns a const char *, casting away the const and modifying the buffer is undefined behavior. The original code doesn't change buffer; removing const attribute by itself cannot cause any problem. For sure, char const* temp = message.c_str(); looks better, but it's not an issue in this case.

Lindley
June 23rd, 2008, 07:53 PM
It's acceptable, but why do it? memcpy's second parameter is a const char* anyway.

lab1
June 24th, 2008, 06:43 AM
Thanks everyone!!!

MrViggy
June 24th, 2008, 11:44 AM
It's acceptable, but why do it? memcpy's second parameter is a const char* anyway.
Dang, I always get that backwards! :D

Viggy