What I'm trying to do here is to cast a stringbuf object into an array of char.
I do this to send the array of char to a C interface which doesn't understand the type std::stringbuf.
Here's a part of my code to illustrate the problem :
std::stringbuf buffer;
char * data;
//here i fill my buffer with an object
buffer >> Myobject;
//here is the function I want to create but I don't know if it's possible
data = convertToCharArray(buffer);
//here I send my buffer of char to my C interface
sendToCInterface(data);
If you don't have a strict zero-copy/high performance requirement then:
std::string tmp = buffer.str();
// call C-interface, it is expected to not save the pointer
sendToCharInterface(tmp.data(), tmp.size());
// call C-interface giving it unique dynamically allocated copy, note strdup(...)
sendToCharInterface(strndup(tmp.data(), tmp.size()), tmp.size());
If you do need it to be fast (yet still have stringbuf on the way) then you can look in the direction of stringbuf::pubsetbuf().
As Kiroxas suggests in the first comment, try to avoid intermediate variables:
sendToCInterface(buffer.str().c_str());
...the less variables the less confusion ;-)
If you would like to convert a std::stringbuf into a char pointer, I think you could just do
std::string bufstring = buffer.str();
to get a string, and convert this into a c-style string using
bufstring.c_str()
to pass a character pointer to a function
Related
I'm having issues with a type conversion that I can't explain.
Here is what i would like to do
I have a buffer that I dynamically allocate and i need to convert it to a string in order to use a parsing function from an external library.
My implementation
unsigned char* msg_data;
msg_data = (unsigned char*)malloc(msg_data_length);
string msg_data_str = std::string(reinterpret_cast<const char*>(_msg_data));
SomeObject myObject;
myObject.ParseFromString(msg_data_str);
But here is the thing : my parsing function fails because it receives the wrong size of data.
Let's say that i have a buffer of size msg_data_length = 10, the size of my string is my_data_str.size() = 14.
I get rid of my problem by using my_data_str.resize(my_data_length)
but I would like to understand why the size of my_data_str is not directly msg_data_length.
Thanks for your help !
I assume that the message data is not actually zero-terminated like a C-style string, which leads to undefined behavior when the std::string constructor is going out of bounds to find the terminator.
To fix this, use the constructor taking two arguments, the string and the length.
See e.g. this std::string constructor reference.
I am new to C++, and haven't quite grasped all the concepts yet, so i am perplexed at why this function does not work. I am currently not at home, so i cannot post the compiler error just yet, i will do it as soon as i get home.
Here is the function.
const char * ConvertToChar(std::string input1, std::string input2) {
// Create a string that you want converted
std::stringstream ss;
// Streams the two strings together
ss << input1 << input2;
// outputs it into a string
std::string msg = ss.str();
//Creating the character the string will go in; be sure it is large enough so you don't overflow the array
cont char * cstr[80];
//Copies the string into the char array. Thus allowing it to be used elsewhere.
strcpy(cstr, msg.c_str());
return * cstr;
}
It is made to concatenate and convert two strings together to return a const char *. That is because the function i want to use it with requires a const char pointer to be passed through.
The code returns a pointer to a local (stack) variable. When the caller gets this pointer that local variable doesn't exist any more. This is often called dangling reference.
If you want to convert std::string to a c-style string use std::string::c_str().
So, to concatenate two strings and get a c-style string do:
std::string input1 = ...;
std::string input2 = ...;
// concatenate
std::string s = input1 + input2;
// get a c-style string
char const* cstr = s.c_str();
// cstr becomes invalid when s is changed or destroyed
Without knowing what the error is, it's hard to say, but this
line:
const char* cstr[80];
seems wrong: it creates an array of 80 pointers; when it
implicitly converts to a pointer, the type will be char
const**, which should give an error when it is passed as an
argument to strcpy, and the dereference in the return
statement is the same as if you wrote cstr[0], and returns the
first pointer in the array—since the contents of the array
have never been initialized, this is undefined behavior.
Before you go any further, you have to define what the function
should return—not only its type, but where the pointed to
memory will reside. There are three possible solutions to this:
Use a local static for the buffer:
This solution was
frequently used in early C, and is still present in a number of
functions in the C library. It has two major defects: 1)
successive calls will overwrite the results, so the client code
must make its own copy before calling the function again, and 2)
it isn't thread safe. (The second issue can be avoided by using
thread local storage.) In cases like yours, it also has the
problem that the buffer must be big enough for the data, which
probably requires dynamic allocation, which adds to the
complexity.
Return a pointer to dynamically allocated memory:
This works well in theory, but requires the client code to free
the memory. This must be rigorously documented, and is
extremely error prone.
Require the client code to provide the buffer:
This is probably the best solution in modern code, but it does
mean that you need extra parameters for the address and the
length of the buffer.
In addition to this: there's no need to use std::ostringstream
if all you're doing is concatenating; just add the two strings.
Whatever solution you use, verify that the results will fit.
This is the scenario;
// I have created a buffer
void *buffer = operator new(100)
/* later some data from a different buffer is put into the buffer at this pointer
by a function in an external header so I don't know what it's putting in there */
cout << buffer;
I want to print out the data that was put into the buffer at this pointer to see what went in. I would like to just print it out as raw ASCII, I know there will be some non-printable characters in there but I also know some legible text was pushed there.
From what I have read on the Internet cout can't print out uncasted data like a void, as opposed to an int or char. However, the compiler wont let me cast it on the fly using (char) for example. Should I create a seperate variable that casts the value at the pointer then cout that variable, or is there a way I can do this directly to save on another variable?
Do something like:
// C++11
std::array<char,100> buf;
// use std::vector<char> for a large or dynamic buffer size
// buf.data() will return a raw pointer suitable for functions
// expecting a void* or char*
// buf.size() returns the size of the buffer
for (char c : buf)
std::cout << (isprint(c) ? c : '.');
// C++98
std::vector<char> buf(100);
// The expression `buf.empty() ? NULL : &buf[0]`
// evaluates to a pointer suitable for functions expecting void* or char*
// The following struct needs to have external linkage
struct print_transform {
char operator() (char c) { return isprint(c) ? c : '.'; }
};
std::transform(buf.begin(), buf.end(),
std::ostream_iterator<char>(std::cout, ""),
print_transform());
Do this:
char* buffer = new char[100];
std::cout << buffer;
// at some point
delete[] buffer;
void* you only need in certain circumstances, mostly for interop with C interfaces, but this is definitely not a circumstance requiring a void*, which essentially loses all type information.
You need to cast it to char*: reinterpret_cast<char*>(buffer). The problem is that void* represents anything, so only th pointer is printed; when you cast it to char*, the contents of the memory are interpreted as a C-style string
Note: use reinterpret_cast<> instead of the C-style (char *) to make your intent clear and avoid subtle-and-hard-to-find bugs later
Note: of course you might get a segfault instead, as if the data is indeed not a C-style string, memory not associated with the buffer might be accessed
Update: You could allocate the memory to a char* buffer to begin with and it would solve your problem too: you could still call your 3rd party function (char* is implicitly convertible to void*, which I presume is the 3rd party function's parameter type) and you don't need to do the cast-ing at all. Your best bet is to zero-out the memory and restrict the 3rd party function to copy more than 99*sizeof(char) bytes into your buffer to preserve the ending '\0' C-style string terminator
If you want to go byte by byte you could use an unsigned char and iterate over it.
unsigned char* currByte = new unsigned char[100];
for(int i = 0; i < 100; ++i)
{
printf("| %02X |", currByte[i]);
}
It's not a very modern (or even very "C++") answer but it will print it as a hex value for you.
I have been working with C++ strings and trying to load char * strings into std::string by using C functions such as strcpy(). Since strcpy() takes char * as a parameter, I have to cast it which goes something like this:
std::string destination;
unsigned char *source;
strcpy((char*)destination.c_str(), (char*)source);
The code works fine and when I run the program in a debugger, the value of *source is stored in destination, but for some odd reason it won't print out with the statement
std::cout << destination;
I noticed that if I use
std::cout << destination.c_str();
The value prints out correctly and all is well. Why does this happen? Is there a better method of copying an unsigned char* or char* into a std::string (stringstreams?) This seems to only happen when I specify the string as foo.c_str() in a copying operation.
Edit: To answer the question "why would you do this?", I am using strcpy() as a plain example. There are other times that it's more complex than assignment. For example, having to copy only X amount of string A into string B using strncpy() or passing a std::string to a function from a C library that takes a char * as a parameter for a buffer.
Here's what you want
std::string destination = source;
What you're doing is wrong on so many levels... you're writing over the inner representation of a std::string... I mean... not cool man... it's much more complex than that, arrays being resized, read-only memory... the works.
This is not a good idea at all for two reasons:
destination.c_str() is a const pointer and casting away it's const and writing to it is undefined behavior.
You haven't set the size of the string, meaning that it won't even necessealy have a large enough buffer to hold the string which is likely to cause an access violation.
std::string has a constructor which allows it to be constructed from a char* so simply write:
std::string destination = source
Well what you are doing is undefined behavior. Your c_str() returns a const char * and is not meant to be assigned to. Why not use the defined constructor or assignment operator.
std::string defines an implicit conversion from const char* to std::string... so use that.
You decided to cast away an error as c_str() returns a const char*, i.e., it does not allow for writing to its underlying buffer. You did everything you could to get around that and it didn't work (you shouldn't be surprised at this).
c_str() returns a const char* for good reason. You have no idea if this pointer points to the string's underlying buffer. You have no idea if this pointer points to a memory block large enough to hold your new string. The library is using its interface to tell you exactly how the return value of c_str() should be used and you're ignoring that completely.
Do not do what you are doing!!!
I repeat!
DO NOT DO WHAT YOU ARE DOING!!!
That it seems to sort of work when you do some weird things is a consequence of how the string class was implemented. You are almost certainly writing in memory you shouldn't be and a bunch of other bogus stuff.
When you need to interact with a C function that writes to a buffer there's two basic methods:
std::string read_from_sock(int sock) {
char buffer[1024] = "";
int recv = read(sock, buffer, 1024);
if (recv > 0) {
return std::string(buffer, buffer + recv);
}
return std::string();
}
Or you might try the peek method:
std::string read_from_sock(int sock) {
int recv = read(sock, 0, 0, MSG_PEEK);
if (recv > 0) {
std::vector<char> buf(recv);
recv = read(sock, &buf[0], recv, 0);
return std::string(buf.begin(), buf.end());
}
return std::string();
}
Of course, these are not very robust versions...but they illustrate the point.
First you should note that the value returned by c_str is a const char* and must not be modified. Actually it even does not have to point to the internal buffer of string.
In response to your edit:
having to copy only X amount of string A into string B using strncpy()
If string A is a char array, and string B is std::string, and strlen(A) >= X, then you can do this:
B.assign(A, A + X);
passing a std::string to a function from a C library that takes a char
* as a parameter for a buffer
If the parameter is actually const char *, you can use c_str() for that. But if it is just plain char *, and you are using a C++11 compliant compiler, then you can do the following:
c_function(&B[0]);
However, you need to ensure that there is room in the string for the data(same as if you were using a plain c-string), which you can do with a call to the resize() function. If the function writes an unspecified amount of characters to the string as a null-terminated c-string, then you will probably want to truncate the string afterward, like this:
B.resize(B.find('\0'));
The reason you can safely do this in a C++11 compiler and not a C++03 compiler is that in C++03, strings were not guaranteed by the standard to be contiguous, but in C++11, they are. If you want the guarantee in C++03, then you can use std::vector<char> instead.
struct testing
{
char lastname[20];
};
testing *pt = new testing;
pt->lastname = "McLove";
and I got
56 C:\Users\Daniel\Documents\Untitled2.cpp incompatible types in
assignment of 'const char[7]' to 'char[20]'
Why ?
Thanks in advance.
Because compile time arrays are constant. In your struct testing, you have an array of 20 chars, and you're trying to assign a pointer ("McLove", a compile time string, e.g., a const char*) to an array (a char[]), which won't work.
To copy the data "McLove" into the array, you need to use strncpy:
strncpy(pt->lastname, "McLove", 20); // 20 is the size of the array, change it when your array size changes, or better yet, use a constant for both
Or better yet, use std::string:
struct testing {
string lastname;
};
testing* pt = new testing;
pt->lastname = "McLove";
And now that will work, because std::string has an operator= that works with const char*.
As a side note, don't needlessly allocate objects on the free store (using new); allocate them on the stack:
testing pt; // not: testing* pt = new testing;
testing.lastname = "McLove"; // with std::string
The type of a string literal is pointer to const char. You can use that to initialize an array of char, but you can't assign to an array of char (from that or anything else).
Since you're apparently doing C++, you probably want:
struct testing {
std::string lastname;
};
testing pt;
pt.lastname = "McLove";
Allocating an object like testing dynamically is fairly unusual.
You can't assign one array to another. You're going to need to use strcpy (or better, strncpy).
Because string literals in C++ have the type const char[N] where N is the length of the literal, including the NULL character. So you're trying to assign a const char[7] to a array of type char[20], exactly what the compiler told you. Since arrays are not assignable this is invalid.
Use strcpy instead
strcpy( p-lastname, "McLove" );
Of course, you should also check if the destination is large enough to hold the source, or use some variant of strcpy that does this.