user8525715
user8525715

Reputation:

How is the type of a pointer implemented in c++?

Pointer types like int*, char*, and float* point to different types. But I have heard that pointers are simply implemented as links to other addresses - then how is this link associated with a type that the compiler can match with the type of the linked address (the variable at this location)?

Upvotes: 0

Views: 133

Answers (3)

James Raynard
James Raynard

Reputation: 19

Variables represent data which is stored in one or more memory cells or "bytes". The compiler will associate this group of bytes with a name and a type when the variable is defined.

The hardware uses a binary number to access a memory cell. This is known as the "address" of the memory cell.

When you store some data in a variable, the compiler will look up the name of the variable and check that the data you want to store is compatible with its type. If it is, it then generates code which will save it in the memory cell(s) at that address.

Since this address is a number, it can itself be stored in a variable. The type of this address variable will be "pointer to T", where T is the type of the data stored in that address.

It is the responsibility of the programmer to make sure that this address variable does correspond to valid data and not some random area of memory. The compiler will not check this for you.

Upvotes: 0

Obsidian
Obsidian

Reputation: 3897

There's no particular "link" at this stage, nor any hidden meta-data stored somewhere. Since C and C++ are compiled and eventually produce a standalone executable, the compiler "trusts" the programmer and simply provides him with a data type that represents a memory address.

If there's nothing explicitly defined at this address, you can use void * pointer. If you know that this will be the location of something in particular, you can qualify it with a certain data type like int * or char *. The compiler will therefore be able to directly access the object that lies behind but the way this address is stored remains the same in every case, and keep the same format.

Note that this qualification is done at compilation time only. It totally disappear in the definitive executable code. This means that this generated code will be produced to handle certain kinds of objects, but nothing will tell you which ones at first if you disassemble the machine code. You'll have to figure this out by yourself.

Upvotes: 0

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275878

Types are mostly compile time things in . A variable's type is used at compile time to determine what the operations (in other C++ code) do on that variable.

So a variable bob of type int* when you ++ it, maps at runtime to a generic pointer-sized integer being increased by sizeof(int).

To a certain extent this is a lie; C++'s behavior is specified in terms of an abstract machine, not a concrete one. The compiler interprets your code as expressing operations on that abtract machine (that doesn't exist), then writes concrete assembly code that realizes those operations (insofar as they are defined) on concrete hardware.

In that abstract machine, int* and double* are not just numbers. If you dereference an int* and write to some memory, then do the same with a double*, and the memory overlaps, in the abstract machine the result is undefined behavior.

In the concrete implementation of that abstract machine, pointers-as-numbers as int* or double* dereferenced with the same address results in quite well defined behavior.

This difference is important. The compiler is free to assume the abstract machine (where int* and double* are very distinct things) is the only reality that matters. So if you write to a int*, write to a double* then read back from the int* the compiler can skip the read back, because it can prove that in the abstract machine writing to a double* cannot change a the value that an int* points to.

So

int buf[10]={0};
int* a = &buff[0];
double* d = reinterpret_cast<double*>(&buff[0]);
*a = 77;
*d = 3.14;
std::cout << *a;

the apparent read at std::cout << *a can be skipped by the compiler. Meanwhile, if it actually happened on real hardware, it would read bits generated by the *d write.

When reasoning about C++ you have to think of 3 things at once; what happens at compile time, the abstract machine behavior, and the concrete implementation of your code. In two of these (compile time and abstract machine) int* is implemented differently than float*. At actual runtime, int* and float* are both going to be 64 or 32 bit integers in a register or in memory somewhere.

Type checking is done at compile time. The error happens then, or never, excluding cases of RTTI (runtime type information).

RTTI is things like dynamic_cast, which does not work on pointers to primitives like float* or int*.

At compile time that variable carries with it the fact it is a int* everywhere it goes. In the abstract machine, ditto. In the concrete compiled output, it has forgotten it is an int*.

Upvotes: 6

Related Questions