struct s
{
int *x; //the pointer is on the stack. the data pointed to could be either on the stack or the heap.
};
struct s2
{
int ** y; //the outer pointer to a pointer is on the stack, the innner pointer itself could be on the heap, and the data pointed to could be stack or heap.
};
are you confusing the pointer variable itself and the data it points to? Those are distinct things and either one can be in either place depending on the details of the code.
even more exciting:
s * sp = new s; //now, sp is likely on the stack, but the struct is and therefore the pointer inside the struct is on the heap... this seems beyond the spirit of the question but you can see why its not enough info to give you an answer?
to answer it another way, are you familiar with the serialization of strings inside objects problem?
if you have
struct s3
{
string data;
};
and you write that to a binary file, the actual text stored in the data string will not be saved... right? It saves the string object, which is a bunch of junk like the size of the string and a pointer (just an integer value). To save the text, you need to serialize it, so you file.write(&data[0], data.length()). You can't read and write these structs directly the way you could if it were
struct s3
{
int i; double d;
}
you are hitting the same idea from the other side. Pointers inside objects are just integer variables, really. The fact that the data inside the integer happens to be a memory address is irrelevant at the binary/compiled object level. Later if you use that integer to get to the memory, that is fine, but the memory itself is not 'inside' the class, its off in another place (assuming its not just the address of a class member variable).
The basic answer to your question is NO. Only the bytes representing the current value of the object are stored on the stack. The "type" is just a matter of how the bytes are interpreted by the program that uses them.
Following up on response from user dutch above, but then how does the program memorize or at least know at the time of usage, what data type that value is? It needs to store it somewhere, no?
Nope. I suppose you could say that it "stores" the type in the executable code.
If the bytes represent a string, then the code that manipulates it will have been designed to manipulate it as a string. If the bytes represent an integer, then the code will manipulate it as an integer. That is all verified at compile time (so-called "static typing", which is a fundamental design feature of C++).
You can reinterpret the bytes as a different type using reinterpret_cast.
#include <iostream>
#include <iomanip>
usingnamespace std;
int main()
{
// store the 8 bytes representing a double value on the stack
double d = 1.234;
// The compiler knows that d's bytes should be interpreted
// as a double, so the code below is compiled to do so.
cout << d << '\n';
// Reinterpret the bytes as an unsigned long
// (I'm assuming long is 8 bytes.)
unsignedlong n = *reinterpret_cast<unsignedlong*>(&d);
// The compiler knows to interpret n as an unsigned long.
cout << "0x" << hex << setfill('0') << setw(8) << n << '\n';
}
When a program is compiled, it just becomes assembly, where higher-level things like C++ types no longer exist. You are only left with basic things like byte, 16-bit integer, 32-bit integer, 64-bit integer, floating-point numbers, and different registers/instructions are needed to work on different types of data.
So to answer your question, the "type" of an instruction is stored through the name of the instruction itself and the registers that it is working with.
For example, when comparing a 64-bit integer to a value, you might get:
cmp rdi, 42
But when comparing a 32-bit integer to A value, the instruction might be:
cmp edi, 42
The key here is that rdi is a 64-bit register, while edi is a 32-bit register.
I tried to run the above code as-is, and get this below error. What am I doing wrong?
datatype.cpp: In function ‘int main()’:
datatype.cpp:15:21: error: ‘reinterpet_cast’ was not declared in this scope
15 | unsigned long n = *reinterpet_cast<unsigned long*>(&d);
| ^~~~~~~~~~~~~~~
datatype.cpp:15:37: error: expected primary-expression before ‘unsigned’
15 | unsigned long n = *reinterpet_cast<unsigned long*>(&d);