I am a beginner in C++. I am working on this project where it is required to trace the memory address. Unfortunately, this tracing function has following prototype declaration:
void TRC(uint8_t, uint8_t, uint8_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, const char*)
Now the options available for me are:
Convert this memory address (pointer value) to uint64_t type. But I've read somewhere that it is not recommended, as pointer value returned by reference operator is platform dependent and conversion of a pointer to an integer may return wrong value.
Convert this memory address to string and pass it via last parameter. In Python it was easy as we had str() function. Do we have something similar in C++ too?
Please let me know if I am inferring something wrong in my approach/understanding here.
You could use streams to convert if it does not need to be fast code.
#include <sstream>
#include <iomanip>
...
std::ostringstream os;
os << std::hex << static_cast<void*>(my_pointer);
TRC(..., os.str().c_str());
You are right in that a pointer should not be stored or passed as any integer types.
If you want to convert a pointer to a printable hexadecimal string, you can use e.g. std::ostringstream:
std::ostringstream os;
os << std::hex << static_cast<void*>(some_pointer);
std::string str = os.str();
TRC(..., str.c_str());
Related
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);
I am learning typecasting.
Here is my basic code, i dont know why after typecasting, when printing p0, it is not showing the same address of a
I know this is very basic.
#include <iostream>
using namespace std;
int main()
{
int a=1025;
cout<<a<<endl;
cout<<"Size of a in bytes is "<<sizeof(a)<<endl;
int *p;//pointer to an integer
p=&a; //p stores an address of a
cout<<p<<endl;//display address of a
cout<<&a<<endl;//displays address of a
cout<<*p<<endl;//display value where p points to. p stores an address of a and so it points to the value of a
char *p0;//pointer to character
p0=(char*)p;//typecasting
cout<<p0<<endl;
cout<<*p0;
return 0;
}
When you pass a char * pointer to the << operator of std::cout, it prints the string that the pointer points to, not the address. It's the same behavior as the following code:
const char *str = "Hello!";
cout << str; // Prints the string "Hello!", not the address of the string
In your case, p0 doesn't point to a string, which is why you're getting unexpected behavior.
The overload of operator<<, used with std::cout and char* as arguments, is expecting a null-terminated string. What you are feeding it with, instead, is a pointer to what was an int* instead. This leads to undefined behavior when trying to output the char* in cout<<p0<<endl;.
In C++, is often a bad idea to use C-style casts. If you had used static_cast for example, you would have been warned that the conversion your are trying to make does not make much sense. It is true that you could use reinterpret_cast instead, but what you should be asking yourself is: why am I doing this? Why am I trying to shoot myself in the foot?
If what you want is to convert the number to string, you should be using other techniques instead. If you just want to print out the address of the char* you should be using std::addressof:
std::cout << std::addressof(p0) << std::endl;
As others have said cout is interpreting the char* as a string, and not a pointer
If you wanted to prove that the address is the same whatever type of pointer it is then you can cast it to a void pointer
cout<<(void*)p0<<endl;
In fact you get the address for pretty much any type other than char&
cout<<(float*)p0<<endl;
To prove to yourself that a char* pointer would have the same value use printf
printf("%x", p0);
cout << sizeof(std::string) << endl;
The result is 8 on my 64-bit machine, which is the same as sizeof(char*), so I am assuming the string class stores only the char*. How, then, is the size function implemented? Is it using strlen (since it is not storing the actual size or the pointer to the ending byte)?
On this page, it shows the size function has a constant time-complexity, so I am confused. And on another page someone has a larger string size.
I am using GCC 4.7.1 on Fedora 64 bit.
There could be many explanations for that. Just because std::string happens to store a pointer and nothing else does not mean that this is necessarily char * pointer to the controlled sequence. Why did you jump to that conclusion?
It could easily turn out that your std::string is a PImpl-style wrapper for a pointer to some internal object that stores all internal household data, including the char * pointer, the length and whatever else is necessary. That way the internal object can be arbitrarily large, without having any effect on the size of std::string itself. For example, in order to facilitate fast reference-counted copying, in some implementations std::string might be implemented similarly to std::shared_ptr. I.e. std::string in that case would essentially become something like std::shared_ptr<std::string_impl> with added copy-on-write semantics.
The target "string implementation" object might even use "struct hack"-style approach to store the actual string, meaning that instead of storing char * pointer it might embed the entire string into itself at the end.
Looking at the doxygen docs for libstdc++:
_CharT* _M_p; // The actual data
Assuming std::basic_string<char>, _M_p is a char* pointer to the actual data, so that is why you are getting 8.
It even says:
Where the _M_p points to the first character in the string, and you
cast it to a pointer-to-_Rep and subtract 1 to get a pointer to the
header.
So, it hides a pointer to the actual representation (capacity, length, etc.) in a block of memory right before where the string data is stored.
Then, there is the following member function to get to the representation:
Rep* _M_rep() const
{ return &((reinterpret_cast<_Rep*> (_M_data()))[-1]); }
and then they call it like this _M_rep()->_M_length; to get the size for example.
Your assumption that std::string is char* is wrong. Here is one of q few possible implementations with sizeof(std::string)==sizeof(char*):
struct std::string
{
string_implementation
{
size_t size;
size_t buffer_size;
char_traits whatever;
char *buffer; // Here is your actual string!
};
string_implementation *ptr;
}
std::string is a typdef for std::basic_string<char>, and basic_string is defined (on my machine) in file /usr/include/c++/4.4/bits/basic_string.h. There's a lot of indirection in that file, but roughly speeking std::string stores a pointer to actual data
// Use empty-base optimization: http://www.cantrip.org/emptyopt.html
struct _Alloc_hider : _Alloc
{
_Alloc_hider(_CharT* __dat, const _Alloc& __a)
: _Alloc(__a), _M_p(__dat) { }
_CharT* _M_p; // The actual data.
};
and this is why you observed such behavior. This pointer might might be casted to obtain pointer to structure that describes the well-known string properties (located just in front of actual data):
struct _Rep_base
{
size_type _M_length;
size_type _M_capacity;
_Atomic_word _M_refcount;
};
_Rep* _M_rep() const
{ return &((reinterpret_cast<_Rep*> (_M_data()))[-1]); }
I'm using C++ map to implemented a dictionary in my program. My function gets a structure as an argument and should return the associated value based on structure.name member which is char named[32]. The following code demonstrates my problem:
map <const char *, const char *> myMap;
myMap.insert(pair<const char *, const char *>("test", "myTest"));
char *p = "test";
char buf[5] = {'\0'};
strcpy(buf, "test");
cout << myMap.find(p)->second << endl; // WORKS
cout << myMap.find("test")->second << endl; // WORKS
cout << myMap.find(buf)->second << endl; // DOES NOT WORK
I am not sure why the third case doesn't work and what should I do to make it work.
I debugged the above code to watch the values passed and I still cannot figure the problem.
Thanks!
Pointer comparison, not string comparison, will be performed by map to locate elements. The first two work because "test" is a string literal and will have the same address. The last does not work because buf will not have the same address as "test".
To fix, either use a std::string or define a comparator for char*.
The map key is a pointer, not a value. All your literal "test" strings share storage, because the compiler is clever that way, so their pointers are the same, but buf is a different memory address.
You need to use a map key that has value equality semantics, such as std::string, instead of char*.
Like was mentioned you are comparing on the address not the value. I wanted to link this article:
Is a string literal in c++ created in static memory?
Since all the literals had the same address this explains why your comparison of string literals worked even though the underlying type is still a const char * (but depending on the compiler it may not ALWAYS be so)
Its because by buf[5] you are allocating the memory pointed by buf but when u use 'p' pointer it points to the same memory location as used by map. So always use std::string in key instead of pointer variable.
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.