C++ - Casting variables and how does it treat them? - c++

I've been pretty curious about this for awhile now maybe I am 100% wrong, but when you cast one type to another does it look at the memory/value and then treat that memory/value as the new type?
For example:
char Letter = 'A';
int iLetter = static_cast<int>(Letter);
//iLetter is 65
If this is correct does it look at the memory location / value of "Letter" and then change the value to represent what ever you are casting it to? I came to this theory by picturing all values as integers and then being casted to the char/struct/class etc.
Hopefully this is a full question, I'd just like a good understanding of how casting really works with the values / information to change them into new values, etc.

In situations when you cast a value (as opposed to a pointer or a reference) the compiler constructs a new value from the one being cast, as opposed to interpreting an existing location as the new type.
Specifically, the code looks at the value of Letter, which is a char, and constructs an iLetter from it by extending the char to an int using the integer conversion rules of C++. This may include sign extension for signed types, so a negative signed char will become a negative int.
On the other hand, when you cast a pointer, the same location is interpreted as a new type.

In your case, static_cast create temp variable with new type and then set it in iLetter.
Edit:
It means static_cast doesn't change the main var type and just read it. at the end, it doesn't directly put the converted value inside iLetter. it will create temp var with new type and that will be set inside iLetter.

What your cast is doing is an implicit conversion, and that means the cast is redundant and not needed, just do this:
int iLetter = Letter; //This is a safe conversion as well
If this is correct does it look at the memory location / value of "Letter"
Yes. Obviously, the value of Letter is looked at, as in the value of the variable seen, otherwise the compiler would have no idea what you are talking about.
- and then change the value to represent whatever you are casting it to?
The original value is not changed, only copied, and that value is casted to the int, to return the character code.

Related

How to get string representation for the member function?

As a part of hashing, I need to convert a function pointer to a string representation. With global/static functions it's trivial:
string s1{ to_string(reinterpret_cast<uintptr_t>(&global)) };
And from here:
2) Any pointer can be converted to any integral type large enough to
hold the value of the pointer (e.g. to std::uintptr_t)
But I have a problems with member functions:
cout << &MyStruct::member;
outputs 1 though in debugger I can see the address.
string s{ to_string(reinterpret_cast<uintptr_t>(&MyStruct::member)) };
Gives a compile-time error cannot convert. So it seems that not any pointer can be converted.
What else can I do to get a string representation?
cout << &MyStruct::member;
outputs 1 though in debugger I can see the address.
There is no overload for ostream::operator<<(decltype(&MyStruct::member)). However, the member function pointer is implicitly convertible to bool and for that, there exists an overload and that is the best match for overload resolution. The converted value is true if the pointer is not null. true is output as 1.
string s{ to_string(reinterpret_cast<uintptr_t>(&MyStruct::member)) };
Gives a compile-time error cannot convert. So it seems that not any pointer can be converted.
Perhaps confusingly, in standardese pointer is not an umbrella term for object pointers, pointers-to-members, pointers-to-functions and pointers-to-member-functions. Pointers mean just data pointers specifically.
So, the quoted rule does not apply to pointers-to-member-functions. It only applies to (object) pointers.
What else can I do to get a string representation?
You can use a buffer of unsigned char, big enough to represent the pointer, and use std::memcpy. Then print it in the format of your own choice. I recommend hexadecimal.
As Martin Bonner points out, the pointer-to-member may contain padding in which case two values that point to the same member may actually have a different value in the buffer. Therefore the printed value is not of much use because two values are not comparable without knowing which bits (if any) are padding - which is implementation defined.
Unfortunately I need a robust solution so because of this padding I can't use.
No portable robust solution exists.
As Jonathan Wakely points out, there is no padding in the Itanium ABI, so if your compiler uses that, then the suggested memcpy method would work.

c++ strings and pointers confusion

string * sptemp = (string *) 0x000353E0;
What does this code exactly want to say ?
I know that in the left side we define a string pointer but I couldn't understand the right part.
It means take a numeric value, convert it to a pointer with that value as the address it points to, and then use that value to initialise the variable sptemp.
If the memory at that address contains a valid string object, then you can use the pointer to access it. If not, trying to do so will give undefined behaviour.
string * sptemp = (string *) 0x000353E0;
What does this code exactly want to say ?
It says, treat the data located at address 0x000353E0 as though it holds a string and assign the address to the variable sptemp. The data can be accessed through the pointer variable sptemp after that.
These comments are mostly right, but not completely. We don't actually know that string is std::string here. It could be that string is a bit of memory-mapped hardware whose address on the OP's embedded SBC is defined by the hardware 0x000353E0. In that case, this is completely sensible, and what people do all the time. The pointer "string *sptemp" is set to point to the hardware interface.
But it's probably nonsense.

Convert pointer to int and back to typed object

I need a simple way to convert a pointer to an int, and then back to the pointer. I need it as an int for portability, since an int is easier to carry around in my project than a pointer.
Start player and return pointer:
SoundPlayer* player = new FxPlayerTiny();
return (int)player; // this works, but is it correct?
Stop player using pointer int:
FxPlayerTiny* player = static_cast<FxPlayerTiny*>((int*)num); // this gives me an error
FxPlayerTiny* player = (FxPlayerTiny*)((int*)obj); // this works, but is it correct?
delete player;
The best thing to do is to fix your project so it can deal with pointers. Integers and pointers are two different things. You can convert back and forth, but such conversions can lose information if you're not careful.
Converting a pointer value to int and back again can easily lose information, depending on the implementation and the underlying platform. For example, there are systems on int is smaller than a pointer. If you have 32-bit ints and 64-bit pointers, then converting a pointer to an int and back again will almost certainly give you an invalid pointer.
It's very likely that long or unsigned long is wide enough to hold a converted pointer value without loss of information; I've never worked on a system where it isn't. (Personally, I tend to prefer unsigned types, but not for any really good reason; either should work equally well.)
So you could write, for example:
SoundPlayer* player = new FxPlayerTiny();
return reinterpret_cast<unsigned long>player;
and convert the unsigned long value back to a pointer using reinterpret_cast,SoundPlayer*>.
Newer implementations provide typedefs uintptr_t and intptr_t, which are unsigned and signed integer types guaranteed to work correctly for round-trip pointer-to-integer-to-pointer conversions. They were introduced in C99, and optionally defined in the <stdint.h> header. (Implementations on which pointers are bigger than any integer type won't define them, but such implementations are rare.) C++ adopted them with the 2011 standard, defining them in the <cstdint> header. But Microsoft Visual C++ does support them as of the 2010 version.
This guarantee applies only to ordinary pointers, not to function pointers or member pointers.
So if you must do this, you can write:
#include <cstdint>
SoundPlayer* player = new FxPlayerTiny();
return reinterpret_cast<std::uintptr_t>player;
But first, consider this. new FxPlayerTiny() gives you a pointer value, and you're going to want a pointer value. If at all possible, just keep it as a pointer. Converting it to an integer means that you have to decide which of several techniques to use, and you have to keep track of which pointer type your integer value is supposed to represent. If you make a mistake, either using an integer type that isn't big enough or losing track of which pointer type you've stored, the compiler likely won't warn you about it.
Perhaps you have a good reason for needing to do that, but if you can just store pointers as pointers your life will be a lot easier.
It is not recommended to use an int for portability, especially because sizeof (int) and sizeof (void*) could differ (for example when compiling for Windows x64).
If ints are needed for a user interface, it maybe would be better to use a table of pointers and accessing them via indices.
However, if you want to convert an pointer to an integer and vice versa a simple conversion is enough but it's just the same, if sizeof *int) == sizeof (void*).

What are the use pointer variables?

I've recently tried to really come to grips with references and pointers in C++, and I'm getting a little bit confused. I understand the * and & operators which can respectively get the value at an address and get the address of a value, however why can't these simply be used with basic types like ints?
I don't understand why you can't, for example, do something like the following and not use any weird pointer variable creation:
string x = "Hello";
int y = &x; //Set 'y' to the memory address of 'x'
cout << *y; //Output the value at the address 'y' (which is the memory address of 'x')
The code above should, theoretically in my mind, output the value of 'x'. 'y' contains the memory address of 'x', and hence '*y' should be 'x'. If this works (which incidentally on trying to compile it, it doesn't -- it tells me it can't convert from a string to an int, which doesn't make much sense since you'd think a memory address could be stored in an int fine).
Why do we need to use special pointer variable declarations (e.g. string *y = &x)?
And inside this, if we take the * operator in the pointer declaration literally in the example in the line above, we are setting the value of 'y' to the memory address of 'x', but then later when we want to access the value at the memory address ('&x') we can use the same '*y' which we previously set to the memory address.
C and C++ resolve type information at compile-time, not runtime. Even runtime polymorphism relies on the compiler constructing a table of function pointers with offsets fixed at compile time.
For that reason, the only way the program can know that cout << *y; is printing a string is because y is strongly typed as a pointer-to-string (std::string*). The program cannot, from the address alone, determine that the object stored at address y is a std::string. (Even C++ RTTI does not allow this, you need enough type information to identify a polymorphic base class.)
In short, C is a typed language. You cannot store arbitrary things in variables.
Check the type safety article at wikipedia. C/C++ prevents problematic operations and functional calls at compliation time by checking the type of the operands and function parameters (but note that with explicit casts you can change the type of an expression).
It doesn't make sense to store a string in an integer -> The same way it doesn't make sense to store a pointer in it.
Simply put, a memory address has a type, which is pointer. Pointers are not ints, so you can't store a pointer in an int variable. If you're curious why ints and pointers are not fungible, it's because the size of each is implementation defined (with certain restrictions) and there is no guarantee that they will be the same size.
For instance, as #Damien_The_Unbeliever pointed out pointers on a 64-bit system must be 64-bits long, but it is perfectly legal for an int to be 32-bits, as long as it is no longer than a long and nor shorter than a short.
As to why each data type has it's own pointer type, that's because each type (especially user-defined types) is structured differently in memory. If we were to dereference typeless (or void) pointers, there would be no information indicating how that data should be interpreted. If, on the other hand, you were to create a universal pointer and do away with the "inconvenience" of specifying types, each entity in memory would probably have to be stored along-side its type information. While this is doable, it's far from efficient, and efficiency is on of C++'s design goals.
Some very low-level languages... like machine language... operate exactly as you describe. A number is a number, and it's up to the programmer to hold it in their heads what it represents. Generally speaking, the hope of higher level languages is to keep you from the concerns and potential for error that comes from that style of development.
You can actually disregard C++'s type-safety, at your peril. For instance, the gcc on a 32-bit machine I have will print "Hello" when I run this:
string x = "Hello";
int y = reinterpret_cast<int>(&x);
cout << *reinterpret_cast<string*>(y) << endl;
But as pretty much every other answerer has pointed out, there's no guarantee it would work on another computer. If I try this on a 64-bit machine, I get:
error: cast from ‘std::string*’ to ‘int’ loses precision
Which I can work around by changing it to a long:
string x = "Hello";
long y = reinterpret_cast<long>(&x);
cout << *reinterpret_cast<string*>(y) << endl;
The C++ standard specifies minimums for these types, but not maximums, so you really don't know what you're going to be dealing with when you face a new compiler. See: What does the C++ standard state the size of int, long type to be?
So the potential for writing non-portable code is high once you start going this route and "casting away" the safeties in the language. reinterpret_cast is the most dangerous type of casting...
When should static_cast, dynamic_cast, const_cast and reinterpret_cast be used?
But that's just technically drilling down into the "why not int" part specifically, in case you were interested. Note that as #BenVoight points out in the comment below, there does exist an integer type as of C99 called intptr_t which is guaranteed to hold any poniter. So there are much larger problems when you throw away type information than losing precision...like accidentally casting back to a wrong type!
C++ is a strongly typed language, and pointers and integers are different types. By making those separate types the compiler is able to detect misuses and tell you that what you are doing is incorrect.
At the same time, the pointer type maintains information on the type of the pointed object, if you obtain the address of a double, you have to store that in a double*, and the compiler knows that dereferencing that pointer you will get to a double. In your example code, int y = &x; cout << *y; the compiler would loose the information of what y points to, the type of the expression *y would be unknown and it would not be able to determine which of the different overloads of operator<< to call. Compare that with std::string *y = &x; where the compiler sees y it knows it is a std::string* and knows that dereferencing it you get to a std::string (and not a double or any other type), enabling the compiler to statically check all expressions that contain y.
Finally, while you think that a pointer is just the address of the object and that should be representable by an integral type (which on 64bit architectures would have to be int64 rather than int) that is not always the case. There are different architectures on which pointers are not really representable by integral values. For example in architectures with segmented memory, the address of an object can contain both a segment (integral value) and an offset into the segment (another integral value). On other architectures the size of pointers was different than the size of any integral type.
The language is trying to protect you from conflating two different concepts - even though at the hardware level they are both just sets of bits;
Outside of needing to pass values manually between various parts of a debugger, you never need to know the numerical value.
Outside of archaic uses of arrays, it doesn't make sense to "add 10" to a pointer - so you shouldn't treat them as numeric values.
By the compiler retaining type information, it also prevents you from making mistakes - if all pointers were equal, then the compiler couldn't, helpfully, point out that what you're trying to dereference as an int is a pointer to a string.

Can I convert a null pointer of int to a long type by reinterpret_cast

int *pt = 0;
long i = reinterpret_cast<long>(pt);
Is i guaranteed to be 0? Is this well defined or implementation-defined?
I checked the c++ standard, but it only states that
A pointer to a data object or to a function (but not a pointer to member) can be converted to any integer type large enough to contain it.
In this case, pt doesn't point to any data object. Does the rule apply to this case?
No, i is not necessarily any value. The result is implementation-defined.†
The representation of pointers, in C++, is implementation-defined, including the representation of a null pointer. When you assign an integer value of zero to a pointer, you set that pointer to the implementation-defined null pointer value, which is not necessarily all-bits-zero. The result of casting that value to an integer is, by transitivity, implementation-defined.
Even more troublesome, though, is that the mapping done by reinterpret_cast is implementation-defined anyway. So even if the null pointer value was all-bits-zero, an implementation is free to make the result whatever it wants. You're only guaranteed that you'll get the original value when you cast back.
That all said, the next sentence after your quote includes the note:
[ Note: It is intended to be unsurprising to those who know the addressing structure
of the underlying machine. —end note ]
So even though specific mappings are not required, pragmatically you can take an educated guess.
† Assuming long is large enough. In C++0x use uintptr_t, optionally defined in <cstddef>.
I don't see why it wouldn't. The issue is that the integer type in question wouldn't be able to hold values that high, but if it's a null pointer there's no problem.
You want reinterpret_cast(pt) but yes, that will work. reinterpret_cast is the same as the old C style cast (long) and assumes you know what you are doing.
Yes, it does not matter where it points at runtime; the only thing that matters is the type of the pointer. "to a data object or to a function" just means that both "regular" object pointers as well as function pointers (i.e. pointers to object code) can be recast into numeric types.
I think the code you have above safely stores 0 to 'i' on all known common platforms.