I have a small websocket server built with libwebsockets , and I need to receive a string , the problem is that the data received is a *void, but I have trouble to cast it to string .
static int my_protocol_callback(struct libwebsocket_context *context,
struct libwebsocket *wsi,
enum libwebsocket_callback_reasons reason,
void *user, void *in, size_t len)
{
int n, m;
unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 +
LWS_SEND_BUFFER_POST_PADDING];
unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
switch (reason) {
case LWS_CALLBACK_ESTABLISHED:
printf("New Connection\n");
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
break;
case LWS_CALLBACK_RECEIVE:
webcmd = static_cast<std::string*>(in);
break;
case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
break;
default:
break;
}
return 0;
}
under the LWS CALLBACK RECEIVE case, the data is *in, and I casted it by static_cast<std::string*>(in);, stored in the webcmd string.
the problem is that the result is a char pointer, instead I need a true char because next I need to split the string.
what do you think about it?
EDIT : resolved the problem .
Under case LWS_CALLBACK_RECEIVE:
tmpcmd = reinterpret_cast <char*>(in);
strcpy(webcmd , tmpcmd );
webcmd is a char array
and tmpcmd is a char pointer
thank you for all :D
You can't just static_cast to anything you like and hope that it is going to work. Unfortunately you are allowed without warning to cast a void* to anything you like.
static_cast, like reinterpret_cast just changes the type a compile-time without any checks as to whether what is pointed to by the pointer actually represents the type you are casting it to.
In this case, a std::string is a complex type with multiple member variables and memory representation. And unless you passed in exactly the same type, you will have catastrophic results.
It would be much better to pass in the actual type, rather than void*, but I don't know if that is possible with what you are doing.
If you really need a string then you need to use one of std::strings constructors.
Like this:
case LWS_CALLBACK_RECEIVE:
std::string command(static_cast<char*>(in));
webcmd = command; //I don't know what webcmd is.
break;
"in" should be some char array , you should do something like this:
char * buf = new char[DATA_SIZE];
and then memory copy the data into it as array of characters (or BYTE).
Once something has been cast to a void*, all type information has been lost.
You need to search through the code / documentation that sets up the callback function and convert back to the data type of the instance that was originally cast to the void*. It may well be a std::string*, but could be other types such as a char*. Then, to make your code really clear, use a reinterpret_cast:
whateverthetypeis* = reinterpret_cast<whateverthetypeis*>(in);
These days, callbacks can be modelled as functors or by using templates. Then the type information is preserved. The mechanism you're currently using is a throwback to the old C days when void* was used as a generic type.
As for wanting a true char; you will not get that. A char is just a number between -128 and +127. However a char* (i.e. a char pointer) is used by C and C++ to model a sequence of non-zero characters starting at the memory location denoted by the char*: i.e. a string.
If it turns out that in is a char*, then you can construct a std::string with in as the constructor argument and split the std::string at your leisure.
Related
I am teaching myself C++ by doing microcontroller projects. My current project is using a pair or Adafruit Feather packet radios. The library functions for the radio packets require a C-style string (I believe) which I understand to be an array of char's.
I have already set up an enum to reflect the various actions of the receiver and would like to send that status back to the transmitter. So I want to turn an enum into an array of char's.
In googling ways to convert enum to array of chars, the easiest (for me to understand) was passing the enum variable to a function with a switch statement that would return a char string. But when I try to put the return into my char array, I get the error "invalid conversion from 'char*' to 'char' [-fpermisive]". I've also been struggling to get my head around arrays and pointers to arrays which is still pretty fuzzy in my head.
Here are some snippets of my code which I hope will show enough of what I'm trying to do.
...from my main function
BLINKING_RIGHT, //0
BLINKING_LEFT, //1
FLASHING, //2
SHOWING_BATTERY,//3
NONE //4
};
...and the two functions that process the enum to send
void SendStatus()
{
char data[20] {EnumToString(currentAction)}; //This is the line showing the error
//itoa (data,static_cast<int>(currentAction),10);
//data[0]=static_cast<uint8_t>(currentAction);
//data[1]=0;
rf69.send(data, sizeof(data));
rf69.waitPacketSent();
Serial.println("Sent a reply");
}//end_function SendStatus()
char* EnumToString(CurrentAction inputEnum)
{
char *statusString;
switch(inputEnum)
{
case 0:
statusString = "BLINKING_RIGHT"; //0
return statusString;
break;
case 1:
statusString = "BLINKING_LEFT"; //1
return statusString;
break;
case 2:
statusString = "FLASHING"; //2
return statusString;
break;
case 3:
statusString = "SHOWING_BATTERY";//3
case 4:
statusString = "NONE"; //4
return statusString;
break;
default:
return "EnumToString: Invalid enum";
}
}
I would like help fixing the problem, and, more importantly, help understanding the difference between the type char* and the type char.
This line:
char data[20] {EnumToString(currentAction)};
Is wrong because it uses array-initialization to initialize the first element of the array of char (first element which is of type char) with a string (char*). What you want to do is something like this:
char data[20];
strcpy(data, EnumToString(currentAction));
Or simply:
char *data = EnumToString(currentAction);
The latter doesn't involve any kind of copying, and efficiency is important on a micro-controller.
While we're on the point of efficiency, the canonical way of mapping sequential enum values to strings is using an array, which is orders of magnitude more efficient than repeated branching:
// stored as read-only data in the .hex file
static char *names[] = { "BLINKING_RIGHT", "BLINKING_LEFT", "FLASHING", "SHOWING_BATTERY", "NONE" };
// later
const char *data = names[currentAction];
Difference between char and char*
char is a character object. Characters are numbers. The number value encodes some textual character (in fixed width character encodings; A C++ character represents one "code unit" in variable width unicode encoding).
char* is a pointer object. It is specifically a pointer to a char object. A pointer object points to another object in memory - or points to nothing if null or points to memory where an object was if the pointer is invalid. Pointers are also iterators, and incrementing a pointer makes it point to a successive element of an array.
char data[20] {EnumToString(currentAction)}; //This is the line showing the error
data is an array of 20 objects of type char. {expr} initialises the first element of the array with the expression. In your case, the expression is a call to EnumToString. Thus, you're attempting to initialise a char object using the char* object returned by the function. The type system of C++ protects you from this obvious mistake.
Assuming you have the option of sending less than 20 bytes, a potential simple solution is to avoid using the local array entirely:
std::string_view str = EnumToString(currentAction);
rf69.send(str.data(), str.size());
char *statusString;
statusString = "BLINKING_RIGHT"; //0
This is ill-formed in C++. String literals are arrays of const char, and they are not convertible to pointer to non-const char (since C++11).
As simple fix is to change the variable and the return type to be const char*. That said, using std::string_view may be even more preferable because that way the caller doesn't need to calculate the length of the string at runtime by searching for the null terminator.
char (or any T) is a value.
char* (or any T*) is a pointer (a value poining to another value, i.e. address).
Keep in mind what arrays (char[] or any T[]) presented by pointer to 0-th element. Variable of char* can point to an element of an array (to the first element in a special case).
I have a class defined like this:
class sco
{
private:
public:
vector<uint8_t> data;
sco(vector<uint8_t> data);
~sco();
};
Where the constructor is:
sco::sco(vector<uint8_t> data) {
this->data = data;
}
I then have a function which is declared like this:
void send(unsigned& id, char* data, char len);
My problem is that I need to pass the data of a sco member to it, but the difference of type and the pointer is confusing me. If I have a member newSco with some data in it, would it be reasonable to call this send function as send(someId, (char*)&(newSco.data.begin()), newSco.data.size() ); ? Please note, that the function send is for a microcontroller, and it takes in char type so I can't change that, and neither can I change uint8_t as that is the type which is coming in from a serial communication. I have wasted over 3 days trying to convert types to something mutual, just to reverse it back because it destroyed everything. I give up and I will no longer try to manipulate the types, as I just do not have that sort of time and just need it to work even if it is bad practice. I thought uint8_t and char are of the same size, so it shouldn't matter.
send(someId, (char*)&(newSco.data.begin()), newSco.data.size() )
You almost had it with this, but not quite.
Here's why:
begin() gives you an iterator. You're taking the address of that iterator, so you're a level of indirection off. Using a C-style cast has masked what would otherwise be a type-related compilation error.
We could write (char*)&*(newSco.data.begin()) instead to dereference the iterator then take the address of the resulting first element.
But if the container were empty, this is very broken. You can't dereference a thing that doesn't exist.
So now we try:
send(someId, (char*)&newSco.data[0], newSco.data.size() )
Unfortunately this is also not safe if the container is empty, since .data[0] also effectively dereferences an element that may not exist. Some argue that the implied &* "cancels it out", but that's controversial and I've never believed it.
If you ever move to C++11 or later, you can use the perfectly safe:
send(someId, (char*)newSco.data.data(), newSco.data.size() )
Otherwise, stick with &newSco.data[0] but skip the entire send call when newSco.data.size() is zero. Can't emphasise that enough.
The cast to char* is itself safe; you can freely interpret uint8_ts as chars in this manner; there's a special rule for it. I've used this pattern myself a few times.
But, as above, a C-style cast is less than ideal. Prefer a nice reinterpret. I'd also add some const for good measure (skip this if your MC's API doesn't permit it):
if (!newSco.data.empty())
{
send(
someId,
reinterpret_cast<const char*>(&newSco.data[0]),
newSco.data.size()
);
}
There. Gorgeous. 😊
As a final note, since the API takes a char for the final parameter, I'd consider putting an upper bound on the container size. You can run the function in a loop, sending either CHAR_MAX or newSco.data.size() bytes at a time (whichever is smaller). Otherwise, if you expect more than CHAR_MAX elements in the container, you're going to get a nasty overflow!
This should work:
send(someId, static_cast<char*>(&newSco.data[0]), static_cast<char>(newSco.data.size()));
Additional Info:
How to convert vector to array
What is the difference between static_cast<> and C style casting?
Yes it is reasonable to cast the pointer to char* in this case. In general, you may not refer to the same memory location with different typed pointers due to strict aliasing rules. However, 'char' is a special case so the cast is allowed.
You shouldn't cast uint32_t* to int32_t though, for example, even though it may work in some cases.
Edit: As the comments below noted: casting from uint8_t* to char* may be fine, casting from iterator is not. use .data() instead of .begin().
If you can use at least C++11, the std::vector class provides data() which returns the raw array.If you are before C++11, I'm afraid you have to iterate over the vector and manually build your char*.
But, you cannot static_cast an unsigned char* to a char*. It is not allowed.But you are lucky, char* is an exception that does not break the strict aliasing rule. So you can use reinterpret_cast instead.
So you may solve your problem as follows:
Before C++11:
std::vector<uint8_t> a; // For the example
a.push_back('a');
a.push_back('b');
a.push_back('c');
a.push_back('d');
char b[a.size()];
for(unsigned int i = 0; i < a.size(); ++i)
{
b[i] = static_cast<char>(a[i]);
}
After C++11:
std::vector<uint8_t> a {'a', 'b', 'c', 'd'}; //uint8_t aka unsigned char
char * b = reinterpret_cast<char*>(a.data()); // b is a char* so the reinterpret_cast is safe
I hope it can help.
try to use reinterpret_cast.
Example:
#include <iostream>
#include <unistd.h>
#include <vector>
int main(int argc, char const *argv[])
{
std::vector<uint8_t> v{65,66,67,68,69,70};
char* ptr = reinterpret_cast<char*>(v.data());
for (auto i{0}; i < v.size(); i++) {
std::cout << *ptr++ << std::endl;
}
return 0;
}
for your case:
void send(someId, reinterpret_cast<char*>(sco.data.data()), sco.data.size());
So I am trying to avoid using strings for this. I am basically trying to make a string array.
char **hourtimes = (char**)malloc(100 * sizeof(char*));
for (int i = 0; i < 100; i++) {
(*hourtimes) = (char*)malloc((100 * sizeof(char)));
}
So I made a string array basically here
Now, I want to make hourtimes[0] = "twelve";
I tried doing *hourtimes = "twelve";
but I get the same error, I think this works in c, but I'm using c++
hourtimes[0][0] = 't';
hourtimes[0][1] = 'w';
etc works just fine but that would be too cumbersome
*hourtimes = "twelve" is setting *hourtimes to point to an immutable string literal. You are then trying to modify that immutable string. What you want to do is copy "twelve" into *hourtimes.
strcpy(hourtimes[0],"twelve");
Note: This answer was written at a time when the question was tagged for C. C++ will have different preferred ways of doing this kind of thing.
The error message tells you exactly what's wrong: You can't assign a const char * to a char *. What does that mean, though?
Both const char * and char * are types. They are, in fact, very nearly the same type; one is a pointer to a character, and the other is a pointer to a constant character. That means that the latter can't be changed1; that's, after all, what "constant" means. So when you try to tell the compiler to treat a pointer to a constant type as a pointer to a non-const type, it'll give you an error -- because otherwise it'd have no way to guarantee that the string isn't modified.
"whatever" is always a const char *, not a char *, because that's stored in memory that's generally not meant to be modified, and the compiler can make some really neat optimizations if it can safely assume that it's unchanged (which, because it's const, it can).
I won't tell you how to "properly" write the code you're going for, because if you're using C++, you should be using std::vector and std::string instead of anything with pointers whenever possible, and that probably includes here. If, for whatever reason, you need to use pointers, the comments have covered that well enough.
1: Okay, yes, it can -- but that's outside the scope of this answer, and I don't want to confuse any beginners.
In your allocation loop, (*hourtimes) is the same as hourtimes[0], so you are assigning your allocated sub-arrays to the same slot in the main array on each loop iteration, causing memory leaks and uninitialized slots. You need to use hourtimes[i] instead:
char **hourtimes = (char**)malloc(100 * sizeof(char*));
for (int i = 0; i < 100; i++) {
hourtimes[i] = (char*)malloc(100 * sizeof(char));
}
And don't forget to deallocate the arrays when you are done with them:
for (int i = 0; i < 100; i++) {
free(hourtimes[i]);
}
free(hourtimes);
Now, a string literal has type const char[N], where N is the number of characters in the literal, + 1 for the null terminator. So "twelve" would be a const char[7].
Your arrays only allow char* pointers to be stored, but a const char[N] decays into a const char* pointer to the first char. You can't assign a const char* to a char*, thus the compiler error.
Even if it were possible to do (which it is, but only with a type-cast), you shouldn't do it, because doing so would cause a memory leak as you would lose your original pointer to the allocated array, and worse free() can't deallocate a string literal anyway.
What you really want to do is copy the content of the string literal into the allocated array storage. You can use strncpy() for that:
strncpy(hourtimes[0], "twelve", 100);
Now, with all of that said, this is the C way of handling arrays of strings. The C++ way is to use std::vector and std::string instead:
#include <string>
#include <vector>
std::vector<std::string> hourtimes(100);
...
hourtimes[0] = "twelve";
This is a string literal, which can be used as a pointer to a constant char, but not as a pointer to a non-const char.
"twelve"
You do however attempt to assign it to a pointer to non-const char.
hourtimes[0] = "twelve";
That is what the compiler does not like.
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.
EDIT: After taking adivce I have rearranged the parameters & types. But the application crashes when I call the digest() function now? Any ideas whats going wrong?
const std::string message = "to be encrypted";
unsigned char* hashMessage;
SHA256::getInstance()->digest( message, hashMessage ); // crash occurs here, what am I doing wrong?
printf("AFTER: n"); //, hashMessage); // line never reached
I am using an open source implementation of the SHA256 algorithm in C++. My problem is understanding how to pass a unsigned char* version of my string so it can be hashed?
This is the function that takes a unsigned char* version of my string:
void SHA256::digest(const std::string &buf, unsigned char *dig) {
init();
update(reinterpret_cast<const unsigned char *>(buf.c_str()), static_cast<unsigned int>(buf.length()));
final();
digest(dig);
}
How can I convert my string(which I want hashed) to an unsigned char*?
The following code I have made causes a runtime error when I go to print out the string contents:
const std::string hashOutput;
char message[] = "to be encrypted";
printf("BEFORE: %s bb\n", hashOutput.c_str());
SHA256::getInstance()->digest( hashOutput, reinterpret_cast<unsigned char *>(message) );
printf("AFTER: %s\n", hashOutput.c_str()); // CRASH occurs here
PS: I have been looking at many implementations of SHA256 & they all take an unsigned char* as the message to be hashed. Why do they do that? Why not a char* or a string instead?
You have the parameters around the wrong way. Buf is the input (data to be hashed) and dig is the output digest ( the hash).
Furthermore, a hash is binary data. You will have to convert said binary data into some string representation prior to printing it to screen. Normally, people choose to use a hexadecimal string for this.
The reason that unsigned char is used is that it has guaranteed behaviours under bitwise operations, shifts, and overflow.
char, (when it corresponds to signed char) does not give any of these guarantees, and so is far less useable for operations intended to act directly on the underlying bits in a string.
The answer to the question: "why does it crash?" is "you got lucky!". Your code has undefined behaviour. In short, you are writing through a pointer hashMessage that has never been initialised to point to any memory. A short investigation of the source code for the library that you are using reveals that it requires the digest pointer to point to a block of valid memory that is at least SHA256_DIGEST_SIZE chars long.
To fix this problem, all that you need to do is to make sure that the pointer that you pass in as the digest argument (hashMessage) is properly initialised, and points to a block of memory of sufficient size. In code:
const std::string message("to be encrypted");
unsigned char hashMessage[SHA256_DIGEST_SIZE];
SHA256::getInstance()->digest( message, hashMessage );
//hashMessage should now contain the hash of message.
I don't know how a SHA256 hash is produced but maybe it involves some sort of arithmetic that needs to be done on a unsigned data type.
Why does it matter? Get a char* from your string object by calling the c_str() method then cast to unsigned char*.