I am working on a function encode data into buffer. I already have functions for the encoding part.
I am encoding and then i push back into a uint8_t vector, which is my output buffer.
For the ints i have no problem, i use my function and everything is done, but now i have to encode a string.
There is already a function made by some developpers before me, which takes as argument char** (buffer to fill), size_t*, and char* which is the string i'm going to encode.
For the char * i just do .c_str() with my string in my C++ object but i don't know what to do about the buffer to fill, because i'm actually using a uint8_t vector.
I thinked about creating a temporary buffer then pushing it in the vector by casting it, is it a good way?
Here is my class (the mother class which is virtual but the string is here so i show you this one):
class CDnsMessage
{
public:
CDnsMessage();
virtual ~CDnsMessage();
virtual void GetSize() = 0;
uint32_t m_ttl;
eDnsClass m_class;
eDnsType m_type;
std::string m_domain;
uint8_t m_sizeDnsCorpse;
uint8_t m_sizeDomainName;
};
The encode part:
std::vector<uint8_t>& output
char * buffer;
std::size_t* bufsz;
EncodeSmallString(*buffer,*bufsz,RR_A_msg->m_domain.c_str());
output.push_back((uint8_t)buffer)
The encoding part needs to look like
char* buffer;
std::size_t bufsz;
EncodeSmallString(&buffer, &bufsize, RR_A_msg->m_domain.c_str());
(You pass in the address of a buffer pointer and size, and the function will allocate the buffer for you.)
Now you need to copy the temporary buffer into your output. This is not a cast, this is a matter of copying each byte. This being C++ there are a zillion ways to do this, but something like:
for (std::size_t i = 0; i<bufsiz;i++) {
output.push_back(static_cast<uint8_t>(buffer[i]));
}
will work (you could also use std::copy or std::vector::insert).
Finally, you need to free the temporary buffer. You will have to look at the documentation of EncodeSmallString to see how to do that - the most likely answers are free or delete[] depending on whether it was allocated with malloc or new [].
I would be very tempted to rewrite EncodeSmallString in terms of appending to a vector, and then write a wrapper overload (with the existing signature) something like:
void EncodeSmallString(char** pbuf, std::size_t* pbufsiz, const char* txt) {
std::vector<uint8_t> temp;
EncodeSmallString(temp, txt);
*pbufsiz = temp.size();
*pbuf = malloc(*pbufsiz); // or new or whatever the existing code uses.
// add error handling to taste
std::copy(*pbuf, temp.begin(), temp.end());
}
Related
I am trying to pass a char * string to a function which will execute inside a thread. The function has the following prototype:
void f(void *ptr);
The thread allocation is made by a function similar to the following:
void append_task(std::function<void(void *)> &f, void *data);
I want to allocate a string that will be used inside the thread. Right Now I have this:
string name = "random string";
char *str = new char[name.length()];
strcpy(str, name.c_str());
append_task(f, static_cast<void *>(str));
I would like to discard the obligation to allocate and deallocate memory manually . How can I do this with std::shared_ptr (namely, the cast to void, and do I guarantee that the string is deallocated when the thread ends?)
P.S. Changing the append_task() function IS an option.
First, ditch the second argument to append_task, and make it take a function with no arguments. Then pass the function by value, not reference. That way, you can just bind the extra data within a lambda, and count on std::string and std::function to do the memory management.
Like so:
void f(void *ptr);
void append_task(std::function<void()> f);
int main()
{
std::string name = "random string";
append_task( [=]{f((void*)name.c_str());} );
}
Firstly there is a dangerous bug in your code:
char *str = new char[name.length()];
strcpy(str, name.c_str());
std::string::length returns the size of the string in bytes excluding the null byte at the end of the string. Then you copy into this buffer with strcpy which reads from a const char * until it hits a null byte into your buffer which is now too short to contain the null byte. You then pass this const char * into a function which now has no idea how long this array is and is probably assuming it to be a null terminated array. This kind of mistake is so common in C that you really need to avoid directly handling C-style strings as much as humanly possible.
As to how to solve your problem I can't improve on the solution using lambdas that Sneftel provides.
This question already has answers here:
Can I get a non-const C string back from a C++ string?
(14 answers)
Closed 5 years ago.
I have a function in a library that takes in a char* and modifies the data.
I tried to give it the c_str() but c++ docs say it returns a const char*.
What can I do other than newing a char array and copying it into that?
You can use &str[0] or &*str.begin() as long as:
you preallocate explicitly all the space needed for the function with resize();
the function does not try to exceed the preallocated buffer size (you should pass str.size() as the argument for the buffer size);
when the function returns, you explicitly trim the string at the first \0 character you find, otherwise str.size() will return the "preallocated size" instead of the "logical" string size.
Notice: this is guaranteed to work in C++11 (where strings are guaranteed to be contiguous), but not in previous revisions of the standard; still, no implementation of the standard library that I know of ever did implement std::basic_string with noncontiguous storage.
Still, if you want to go safe, use std::vector<char> (guaranteed to be contiguous since C++03); initialize with whatever you want (you can copy its data from a string using the constructor that takes two iterators, adding a null character in the end), resize it as you would do with std::string and copy it back to a string stopping at the first \0 character.
Nothing.
Because std::string manages itself its contents, you can't have write access to the string's underlying data. That's undefined behavior.
However, creating and copying a char array is not hard:
std::string original("text");
std::vector<char> char_array(original.begin(), original.end());
char_array.push_back(0);
some_function(&char_array[0]);
If you know that the function will not modify beyond str.size() you can obtain a pointer in one of different ways:
void f( char* p, size_t s ); // update s characters in p
int main() {
std::string s=...;
f( &s[0], s.size() );
f( &s.front(), s.size() );
}
Note, this is guaranteed in C++11, but not in previous versions of the standard where it allowed for rope implementations (i.e. non-contiguous memory)
If your implementation will not try to increase the length of the string then:
C++11:
std::string data = "This is my string.";
func(&*data.begin());
C++03:
std::string data = "This is my string.";
std::vector<char> arr(data.begin(), data.end());
func(&arr[0]);
Here's a class that will generate a temporary buffer and automatically copy it to the string when it's destroyed.
class StringBuffer
{
public:
StringBuffer(std::string & str) : m_str(str)
{
m_buffer.push_back(0);
}
~StringBuffer()
{
m_str = &m_buffer[0];
}
char * Size(int maxlength)
{
m_buffer.resize(maxlength + 1, 0);
return &m_buffer[0];
}
private:
std::string & m_str;
std::vector<char> m_buffer;
};
And here's how you would use it:
// this is from a crusty old API that can't be changed
void GetString(char * str, int maxlength);
std::string mystring;
GetString(StringBuffer(mystring).Size(MAXLEN), MAXLEN);
If you think you've seen this code before, it's because I copied it from a question I wrote: Guaranteed lifetime of temporary in C++?
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.
i have a member function in which i need to get some char array at run time
My fear
Is if i try
delete buffer;
then i cant
return buffer;
But how to i release the memory i allocated with
char * buffer= new char[size]
The class
class OpenglShaderLoader
{
char * getLastGlslError()
{
char * buffer;//i don't know the size of this until runtime
int size;
glShaderiv(hShaderId,GL_INFO_LOG_LENGTH,&size);//get size of buffer
buffer= new char[size];
//.. fill in the buffer
return buffer;
}
}
You should return a std::vector<char>. That way, when the caller finishes using the vector, its contents are freed automatically.
std::vector<char> getLastGlslError()
{
int size;
glShaderiv(hShaderId, GL_INFO_LOG_LENGTH, &size);
std::vector<char> buffer(size);
// fill in the buffer using &buffer[0] as the address
return buffer;
}
There is a simple adage - for every new there must be a delete, in your case, in relation to the class OpenglShaderLoader, when you call getLastGlsError, it returns a pointer to the buffer, it is there, that you must free up the memory, for example:
OpenglShaderLoader *ptr = new OpenglShaderLoader();
char *buf = ptr->getLastGlsError();
// do something with buf
delete [] buf;
You can see the responsibility of the pointer management rests outside the caller function as shown in the above code example/
You'd need another method, such as:
void freeLastGlslError(const char* s)
{
delete [] s;
}
But since you're using C++, not C, you shouldn't return a char*. For an object-oriented design, use a string class that manages the memory for you, like std::string. (Here's the litmus test to keep in mind: if memory is being freed outside of a destructor, you're probably doing something inadvisable.)
Here's a trick how to do it:
class A {
public:
A() : buffer(0) { }
char *get() { delete [] buffer; buffer = new char[10]; return buffer; }
~A() { delete [] buffer; }
private:
char *buffer;
}
When you return that pointer, whatever you're returning the pointer to should assume responsibility over that resource (i.e. delete it when done with it).
Alternatively, you can use a smart pointer to automatically delete the memory for you when nothing points to it.
Creating and returning a stl container or class (e.g. std::vector, std::string) is also a viable option.
Don't return a primitive char*. Encapsulate it in a class.
Assuming that the char array is really not a NULL terminated string, you need to include the size of it on return anyway. (It is sort of messy to continuously call glShaderiv to get the length, especially if it has performance implications. Easier to store the size with the allocation.)
Some have suggested using std::string or std::vector as the return. While each of these will work to a varying degree, they don't tell you what it is that is in each instance. Is it a string you print or is it an array of signed 8 bit integers?
A vector might be closer to what you need, but when you're looking at the code a year from now you won't know if the output vector of one method contains shader info when compared to another method that also returns a vector. There may also be implications of vector that make it undesirable for things like filling the buffer by passing a pointer to a device driver method since the storage is technically hidden.
So putting the return in a class that allocates your buffer and stores the size of the allocation allows you to let the return instance go out of scope and delete the buffer when the caller is done with it.
now body mentioned managed pointers yet?
If you don't need the features of a vector then ::array_ptr<char> might also help rather than rolling your own as in tp1's answer. Depending on version of compiler, available in boost/TR1/std.
boost::array_ptr<char> getLastGlslError()
{
int size;
glShaderiv(hShaderId, GL_INFO_LOG_LENGTH, &size);
boost::array_ptr<char> buffer = new char[size];
return buffer;
}