I am working in a mqtt application and when i receive the information of the payload from the mqtt broker and try to convert it from the void* that is message->payload to an int as
signed int var_1=*((int*) message->payload);
instead of converting it to the number it is converting it to another one, to see this I am using the following code:
printf("Message:%s\n",message->payload);
printf("Message:%i\n",var_1);
Which shows:
Message:-58
Message:3683629
I also thought about the payload being a string, but if I use the stoi function it gives me the error:
can not convert from ´void*´ to ´int´ with stoi function.
In C++ you can't automatically convert from const void* to const char*.
You need an explicit static cast:
int i=atoi(static_cast<const char*>(message->payload));
Notice I've used atoi() which is a C library function (#include <cstdlib>).
There's little point converting it to a std::string just to parse that to an int.
All this assumes you're correct to think the payload is a character encoded decimal integer in a c-style string.
[I] try to convert it from the void* ... to an int.
OK. The first step is to figure out the type of object that is being transported. As the documentation of MQTT says:
MQTT is data-agnostic and it totally depends on the use case how the payload is structured. It’s completely up to the sender if it wants to send ...
as
signed int var_1=*((int*) message->payload);
Now, this is correct, if the pointer points to an object of type int. It is a reasonable guess, but you should not be guessing - except as last resort - for the type of the object. You should study the sender whether by reading documentation or code to find out the type of the pointed object.
instead of converting it to the number it is converting it to another one
So, either you've been expecting the wrong value, or you guessed the type wrong. The solution is to stop guessing and find out the correct type.
I also thought about the payload being a string, but if I use the stoi function it gives me the error:
can not convert from ´void*´ to ´int´ with stoi function.
The error seems to be exceptionally clear. The argument of stoi is const std::string& str, not void*. void* is not implicitly convertible to std::string. Exactly how to do such conversion depends on what type of object void* points to (or sometimes, what type of data it contains).
I didn't quite understand if message->payload holds the number itself or a string representation for it.
If message->payload holds the memory location in which the number is stored, so var_1 holds the value.
Therefore, you cannot expect those values to be the same.
Regarding stoi - it receives a string that hold number, but as a string. For example -
std::string num = "1234";
int convertedNumber = stoi(num);
Related
[EDIT]I wanted write uint64_t to char* array in network byte order to send it as UDP datagram with sendto, uint64_t has 8 bytes so I convert them as follow:
void strcat_number(uint64_t v, char* datagram) {
uint64_t net_order = htobe64(v);
for (uint8_t i=0; i<8 ;++i) {
strcat(datagram, (const char*)((uint8_t*)&net_order)[i]);
}
}
wchich give me
warning: cast to pointer from integer of different size [-Wint-to-pointer-xast]
strcat(datagram, (const char*)((uint8_t*)&net_order)[i]);
how can I get rid of this warning or maybe do this number converting simpler or clearer?
((uint8_t*)&net_order)
this is a pointer to net_order casted to a uint8_t pointer
((uint8_t*)&net_order)[i]
this is the i-th byte of the underlying representation of net_order.
(const char*)((uint8_t*)&net_order)[i]
this is the same as above, but brutally casted to a const char *. This is an invalid pointer, and it is what the compiler is warning you about; even just creating this pointer is undefined behavior, and using it in any way will almost surely result in a crash.
Notice that, even if you somehow managed to make this kludge work, strcat is still the wrong function, as it deals with NUL-terminated strings, while here you are trying to put binary data inside your buffer, and binary data can naturally contain embedded NULs. strcat will append at the first NUL (and stop at the first NUL in the second parameter) instead of at the "real" end.
If you are building a buffer of binary data you have to use straight memcpy, and most importantly you cannot use string-related functions that rely on the final NUL to know where the string ends, but you have to keep track explicitly of how many bytes you used (i.e. the current position in the datagram).
I have the function below in a file called WiServer.h for Arduino.
GETrequest(uint8* ipAddr, int port, char* hostName, char* URL);
Now the problem is I need to concatenate an int value (setting1) to the char* URL parameter like the below for example.
"twittermood.php?status=sendTweet&setting1="+setting1
I get an error:
invalid conversion from const char* to char*
How do I fix it?
You've gotten decent generic C++ advice, but for the special case of Arduino on an 8-bit AVR microcontroller I think you need platform-specific advice:
The Arduino runtime provides a String object. Your question is probably covered by these examples.
Because of the very limited RAM space on Arduino it is common to use special attributes to put constant strings in flash (essentially ROM) which requires different instructions to access. AVR code built with GCC is typically built on top of AVR Libc which has support for operating on a mix of constant strings and RAM strings. You must be explicit in your code and choose the right operations. This requires at least a basic understanding of how C strings work and how pointers work. I'm not sure how much of this cleverness is automatically provided by the Arduino String, but without this cleverness all of your string constants will end up copied into RAM at boot and will take up those precious bytes all the time.
If RAM space becomes a problem or you are working on an AVR application that does extensive string manipulation you need to learn how to use the mix of PGM Space operations (string functions that can work on read-only strings in flash) and regular C-style RAM-based string operations.
Use std::string, rather than C strings. Use string streams, rather than trying to concatenate non-string values to strings:
std::ostringstream oss;
oss << "twittermood.php?status=sendTweet&setting1=" << setting1;
use(oss.str()); // or use(oss.str().c_str());
If that API really needs a non-const string (given that it doesn't even take the length of the string, I suppose it's just a buggy API disregarding const), copy the string to a buffer and pass that:
const std::string& str = oss.str();
std::vector<char> buffer(str.begin(), str.end());
buffer.push_back('\0');
GETrequest(addr, port, &buffer[0], c);
As for what really happens when you do what you do:
"twittermood.php?status=sendTweet&setting1=" is an rvalue of the type char[43], which implicitly converts to const char*, a pointer to the first character. To that you add an integer, by this forming a new pointer of the type const char* pointing to some more or less random memory location. I suppose you try to pass this as the char* to your API function, for which the const would have to be dropped.
A C++ compiler, however, will never implicitly drop a const — for your own good.
Use a std::string, not a char*, for this sort of work. A char* in C is extremely basic and if you're not familiar with how C works, very easy to use wrong.
If you need to use char*, look into strcpy, strcat and snprintf. But these functions are very dangerous in a novice's hands and can lead to memory corruption and crashing.
You can use an ostringstream for this:
#include <sstream>
// ...
std::ostringstream os;
os << "twittermood.php?status=sendTweet&setting1=" << setting1;
GETrequest(addr, port, hostname, os.str().c_str());
Use std::string instead of char* and maybe a std::stringstream for your concatination. But first about your errors:
Your problem is that "twittermood.php?status=sendTweet&setting1=" will get you a const char*, which can't be implicitely converted to a char*. If you are really sure that GETrequest doesn't try to change the value of its URL parameter, you can use const_cast<char*>(...) on your const char* variable to cast away the constness. However, do this only if you are absolutely sure it won't be changed (don't lie to the compiler about constness (or anything really)).
Even if you do that "twittermood.php?status=sendTweet&setting1="+setting1 won't do what you think it does. As I said your string constant will give you a const char*, which doesn't have any knowledge about string operations. So adding an intto it won't concat that int to the string, but instead do some pointerarithmetic, so if you are lucky and your int was small enough you get only a part of the URL, otherwise you will address something completely different.
Posting C solution for completeness:
const char ctext[] = "twittermood.php?status=sendTweet&setting1=";
char text[sizeof(ctext) + 20];
snprintf(text, sizeof(text), "%s%i", ctext, setting1);
std strings and streams are much nicer/safer to use.
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*.
I have a char* name which is a string representation of the short I want, such as "15" and need to output this as unsigned short unitId to a binary file. This cast must also be cross-platform compatible.
Is this the correct cast: unitId = unsigned short(temp);
Please note that I am at an beginner level in understanding binary.
I assume that your char* name contains a string representation of the short that you want, i.e. "15".
Do not cast a char* directly to a non-pointer type. Casts in C don't actually change the data at all (with a few exceptions)--they just inform the compiler that you want to treat one type into another type. If you cast a char* to an unsigned short, you'll be taking the value of the pointer (which has nothing to do with the contents), chopping off everything that doesn't fit into a short, and then throwing away the rest. This is absolutely not what you want.
Instead use the std::strtoul function, which parses a string and gives you back the equivalent number:
unsigned short number = (unsigned short) strtoul(name, NULL, 0);
(You still need to use a cast, because strtoul returns an unsigned long. This cast is between two different integer types, however, and so is valid. The worst that can happen is that the number inside name is too big to fit into a short--a situation that you can check for elsewhere.)
#include <boost/lexical_cast.hpp>
unitId = boost::lexical_cast<unsigned short>(temp);
To convert a string to binary in C++ you can use stringstream.
#include <sstream>
. . .
int somefunction()
{
unsigned short num;
char *name = "123";
std::stringstream ss(name);
ss >> num;
if (ss.fail() == false)
{
// You can write out the binary value of num. Since you mention
// cross platform in your question, be sure to enforce a byte order.
}
}
that cast will give you (a truncated) integer version of the pointer, assuming temp is also a char*. This is almost certainly not what you want (and the syntax is wrong too).
Take a look at the function atoi, it may be what you need, e.g. unitId = (unsigned short)(atoi(temp));
Note that this assumes that (a) temp is pointing to a string of digits and (b) the digits represent a number that can fit into an unsigned short
Is the pointer name the id, or the string of chars pointed to by name? That is if name contains "1234", do you need to output 1234 to the file? I will assume this is the case, since the other case, which you would do with unitId = unsigned short(name), is certainly wrong.
What you want then is the strtoul() function.
char * endp
unitId = (unsigned short)strtoul(name, &endp, 0);
if (endp == name) {
/* The conversion failed. The string pointed to by name does not look like a number. */
}
Be careful about writing binary values to a file; the result of doing the obvious thing may work now but will likely not be portable.
If you have a string (char* in C) representation of a number you must use the appropriate function to convert that string to the numeric value it represents.
There are several functions for doing this. They are documented here:
http://www.cplusplus.com/reference/clibrary/cstdlib
I need to pass one of my parameters to a write() function. It is asking for a type of 'const void*' I am a PHP guy and don't know C++ very well.
Here is my parameter:
const fmx::Text& distance = dataVect.AtAsText(3);
I don't know of any other way to pull in that field. I would love to just declare it const void* but I don't know how.
I guess just converting it would be easier than trying to pull it in the correct way??
The error message: cannot convert const fmx::Text to const void* for argument 2
write(fd, distance, 4);
I know this worked so can I just convert?
const void* s = "5000";
This is for a plugin in FileMaker so I don't really get c++ here.
Is there more anyone would need to help me solve this??
Thanks so much!
If fmx::Text was a pointer type, the compiler would automatically convert a reference to it into a void*. You need to use the address-of operator to give the function a pointer to work with:
write(fd, &distance, 4);
I don't really know filemaker, but this link shows that fmx::Text has a GetBytes function. You can then pass the pointer to the buffer filled with this function.
I'm assuming you actually want the text string.
I think you need to check the api for fmx::Text to get the string you want. Here is something I found to get the string out.
Looks like the type stores the data as UTF16, so you have to run a bit of code to get a string out, then pass it to your write function:
//a function to convert to a normal string
std::string getString(fmx::Text& Text)
{
char buffer[512] = {0}; //NOTE YOU HAVE A STRING SIZE LIMIT
// convert original text to ASCII text
outText.GetBytes( buffer, sizeof(buffer)-1, 0, Text.GetSize(), fmx::Text::kEncoding_Native );
return buffer;
}
Then call the function
std::string myString = getString(distance);
write(fd, myString.c_str(), myString.size());
Note I'm assuming a lot here...that you want a string in the current encoding, and not the raw UTF16 data from 'distance'. AND that GetBytes will not mangle the null characters in buffer....
You'll also need to include <string> in your c++ file.