#so im learning about type punning and i want u to tell me if im understanding this right or no

486 messages · Page 1 of 1 (latest)

heavy basalt
#
#include <iostream>

struct entity {
    int x, y;
};

int main() {
    entity e = { 5, 8 };

    int* pos = (int*)&e;

    std::cout << pos[0] << ", " << pos[1] << std::endl;
}

so if i look at this code, &e get the memory address, when u cast it with an int pointer, its basically telling its an int and the pointer is telling the location of that e object memory address, and then store those memory to the int* pos? so basically ur just changing the memory location to a different memory?

magic galeBOT
#

When your question is answered use !solved to mark the question as resolved.

Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.

heavy basalt
#

also why do u need to cast int pointer to the &e? doesnt it already get the e object address? im confused

random tinsel
#

what type is &e ?

heavy basalt
#

a type pointer?

#

idk

random tinsel
#

it's an entity*

#

entity pointer.

heavy basalt
#

oh

#

so basically when ur creating new object of the struct entity, its just storing the object to the entity memory?

#

is it correct?

#

correct or wrong

random tinsel
#

when learning pointers and objects, etc. it's best not to even mention 'memory' until later.

heavy basalt
#

so do i say address

random tinsel
#

you create objects. you can point at them, you can take the address-of, you can make pointers, you can cast pointers. etc. the fact all this gets implemented in memory is just implementation details.

heavy basalt
#

ok

heavy basalt
#

or am i wrong

random tinsel
#

yes. it's C style cast, which is already a bad choice. but it is casting your entity* into a int*

heavy basalt
#

what does that do tho

random tinsel
#

which doesn't make a whole lot of sense.

heavy basalt
#

does it locate where is the object address from?

random tinsel
#

you're talking about implementation details again. that's irrelevant at this point.

#

you cast you pointer of 1 type into a pointer of another type.

#

presumably caues you are trying to make a int* called pos

heavy basalt
#

what

#

can u reexplain that again

#

what did int* cast to entity* do

#

my brain goes blank

random tinsel
#

everything has a type.

heavy basalt
#

so entity* cast to int*?

heavy basalt
#

im so lost

random tinsel
#

entity is a type. you created it. it's name is e.

#

int i; int is a type. it's name is i

heavy basalt
#

oh

#

but i dont understand casting it with each other will do something

#

what is the process

random tinsel
#

what type is e ?

heavy basalt
#

entity

random tinsel
#

what type is &e

heavy basalt
#

entity*

random tinsel
#

what type is (int*)&e

heavy basalt
#

uhhh

#

int* entity*?

#

idk what

random tinsel
#

just a int* int pointer.

heavy basalt
#

huh?

#

how

#

how did the entity* dissapear

random tinsel
#

cause (int*) converted it into that

heavy basalt
#

oh so u coverted the entity* to an int*?

random tinsel
#

(T*) infront of another pointer converts it to a pointer of type T

heavy basalt
#

so basically doing that will make it able to store it in the int* pos?

random tinsel
#

what type is pos

heavy basalt
#

u could just say entity* is converted to an int* at the beginning

heavy basalt
#

one more thing

heavy basalt
#

does it look like int* e

random tinsel
#

'that' is ambigous. be specific.

heavy basalt
#

i mean how does it look like when its converted to an int pointer?

#

does it look like int* e? int* something idk

#

hello?

heavy basalt
heavy basalt
#

what

#

i just want to know

sinful kernel
#

But its
(int*)entityptr

#

Where entityptr is just a variable with type entity*

heavy basalt
#

so it just look like (int*)entityptr?

sinful kernel
#

Yes

#

But you usually don't typecast pointers like this in c++

magic galeBOT
#
How to Learn C++ Programming

We generally recommend a good book to learn the necessary fundamentals:

To actually write and run C++ code, you will need a compiler, editor, and debugger. We strongly recommend to start out using an IDE, which will provide all these tools for you:

<:microsoft:1165512917047853127> Windows
  • [Visual Studio](#1165492293810257920 message)
  • CLion
<:tux:1165505626894520361> Linux
<:apple:1165508607798943754> Mac
Words of Advice

The wise programmer is told about the debugger and uses it.
The average programmer is told about the debugger and avoids it.
The foolish programmer is told about the debugger and laughs at it.

heavy basalt
#

i don't understand, I thought entityptr is a type and when u cast it with intptr the entityptr be replaced with the int

sinful kernel
#

learncpp surely explains it better than me

heavy basalt
#

ok

heavy basalt
sinful kernel
heavy basalt
#

ill take a bath brb I'll read after im done

sinful kernel
#

I could've called it anything

heavy basalt
#

is it like that

#

is it like that

#

@sinful kernel yo answer me pls 😭

sinful kernel
#

Casting it to an int pointer makes no sense.

heavy basalt
#

what

#

😦

sinful kernel
#

Because why would you want a type that should be pointing to an integer to point to an entity

heavy basalt
#

i still don't understand tbh

sinful kernel
#

int* is meant to point to integers
entity* is meant to point to entities

heavy basalt
#

wait lemme think

sinful kernel
#

Thus, casting an entity* to int* make no sesne

heavy basalt
#

i mean like (int*)&e

sinful kernel
#

You don't really cast pointers in c++ anyways 🤷‍♂️

#

Or at least not like this

heavy basalt
# heavy basalt i mean like (int*)&e

it's just storing the object address to the "int*" right? And then the intptr pos is just like saying entity pos? pos is the name of the object or im tripping

sinful kernel
#

what?

#

int* is a pointer to an integer

#

It's better to avoid saying anything about memory or addresses for now

heavy basalt
#

(int*)&e is like saying (intptr)entityptr right?

sinful kernel
#

intptr isn't a valid type I think

heavy basalt
#

so what is it

sinful kernel
#

I don't know, you brought it up

heavy basalt
#

bro u said it's not a valid type what is it im confused

sinful kernel
#

intptr is not a type in c++

heavy basalt
#

so what does (int*)&e do

#

bro I'm more confused than before

sinful kernel
#

Well if you don't know what a pointer is then you won't understand casting them either

#

You won't be able to bake bread without knowing what bread is

heavy basalt
#

(int*)&e

is this like converting the &e object to an intptr so like it's an int type and not an entity type so u can out it at intptr position or smth?

sinful kernel
#

"out ut at intptr position" what do you mean by that?

heavy basalt
sinful kernel
#

Put it? Where

heavy basalt
#
#include <iostream>

struct entity {
    int x, y;
};

int main() {
    entity e = { 5, 8 };

    int* pos = (int*)&e;

    std::cout << pos[0] << ", " << pos[1] << std::endl;
}

position is pos

sinful kernel
#

Okay that's not how it works

heavy basalt
#

is it kinda correct

random tinsel
#

learn to use backtick's as you type this stuff. so it's clear your talking about code. like this

sinful kernel
sinful kernel
#

I mean that it works but it's cursed

heavy basalt
#

I'm talking about types like since I can't do intptr pos = &e bc its an entity type so u convert it to an int* right?

limpid elm
heavy basalt
#

explain like a noob, my brain can't handle it

sinful kernel
limpid elm
#

When you declare int a = 4 what do you think happens, what does computer do?

sinful kernel
#

Its int*

heavy basalt
#

ik

#

I'm just saying intptr so that discord don't make it as a font

#

😢

limpid elm
#

\*

#

there's formatting

heavy basalt
#

did u just mistaken everything I said bc of me saying intptr

limpid elm
#

so use \* to get *

sinful kernel
#

Use codeblocks

heavy basalt
#

\

Tes

#

huh

#

\ tes

sinful kernel
#

Still, your code working makes sense, but it's another question if you understand why or not

heavy basalt
#
  • t *
sinful kernel
#

Because from what I've read, you don't

heavy basalt
#

Jajak * t *

#

oh u need to put some space to it

limpid elm
heavy basalt
limpid elm
#

do you have any idea what computer does when you declare variable

#

can you explain it to me?

heavy basalt
#

uhh

#

make new byte

#

???

limpid elm
#

well 1b? what about int? do you know the size of an int?

heavy basalt
#

i forgot

limpid elm
#

4b

heavy basalt
#

i remember studying it

heavy basalt
limpid elm
#

mind that the size of a primitive type can depend on architecture

#

but then again let's focus on this one

heavy basalt
#

ok

limpid elm
#

4 bytes, so when you create variable of a type int

#

you tell the compiler/computer

#

to allocate 4 bytes for you

heavy basalt
#

ok

limpid elm
#

compiler does not know the address per se, cause it's your system that decides where it places new instance of your program

heavy basalt
#

wait how's this going to make me understand how (int*)&e works

limpid elm
#

step by step

#

but we have special place, every process in the system gets it, that we call a stack

#

you can think of it as a frame of memory with bunch of boxes

heavy basalt
#

storage for each memory?

limpid elm
#

yeah, dedicated storage for variables, not all of them

#

mostly the temporary ones

heavy basalt
#

ok

#

now what

limpid elm
#

memory has address you can refer to, when writting a program we use labels, we don't know what address they will have

#

at least usually

#

labels are then compiled into offsets from the beggining of the stack

#

or the memory of the program

#

depending on where they are placed

#

so when you are creating a variable, it's just value placed at the address in memory

#

now to the point

heavy basalt
#

ok

limpid elm
#

when we are talking about types

#

it's not just about size

#

it's also it's interpretation

#

for example floating point types

#

like float and double have their own representation

#

and to calculate these cpu has special modules to deal with that interpretation correctly

#

integers are calculated differently

#

there's also difference between int and unsigned int right?

heavy basalt
#

i want to know what's that "unsigned"

#

does it mean no value

limpid elm
#

technically it tells the compiler that that memory should never be interpreted as negative number

#

> 0 only

heavy basalt
#

oh ok

#

continue

limpid elm
#

technically in memory it does not differ from an int, read about U2 notation

#

ok so let's go with example

heavy basalt
#

Ok

limpid elm
#
int main() {
  int a = 4;
  int* a_ptr = &a;
}
#

all it does is declares integer labeled a and pointer to it

#

you already know that a has it's own address

heavy basalt
limpid elm
#

to be exact the address of a is assigned to the pointer

heavy basalt
#

yes

limpid elm
#

pointer is like a variable, but one that stores addresses

heavy basalt
#

yeah ik

limpid elm
#

and since we also informed the compiler of the type to which we are pointing to

#

we also know how to interpret it

heavy basalt
limpid elm
#

yeah

heavy basalt
#

ok continue

limpid elm
#
int main() {
  int a = 4;
  int* a_ptr = &a;
  float* a_ptr_asfloat = &a;
}
#

this from our perspective

#

would seem to point to an integer but interpret is as flot

#

they have the same size, so in that sense it's fine

heavy basalt
#

so it'll cause an error?

limpid elm
#

yep, cause compiler wants to make sure

heavy basalt
#

oh ok

limpid elm
#

such things aren't possible, it could cause a lot of trouble

heavy basalt
limpid elm
#

it will, you are pointing to and int with pointer to float

#

even if it didn't warn/error then it's basically undefined behaviour

#

out of nowhere you started treating int as float

#

hard to expect what number it wil lbe

#

since they have different representation

heavy basalt
limpid elm
#

in memory

#

yeah

#

compiler wants you to be safe about it, that you won't mistakenly do something stupid, not intended

heavy basalt
#

now how do u change it to an int

limpid elm
#

wdym?

heavy basalt
#

i mean to float

#

like int to float

limpid elm
#

you mean like the value of a to float version of it?

heavy basalt
#

yeah

limpid elm
#

assuming that float can store that value (different representation, doesn't allow us to store exactly the same range of values)

heavy basalt
#

do u just do (float*)&a

limpid elm
#

C cast would be (float)a, C++ cast would be static_cast<float>(a), C casts are safer

#

oh you meant you wanted punning

#

let me get to that

heavy basalt
#

ye

limpid elm
#

now punning is basically what we call circumventing type system checks

#

highly dangerous

heavy basalt
limpid elm
#

best if you don't ever do it

#

it would be right, if you wanted to shoot yourself in the foot

#

yeah

#

it would pun it to float

#

bad idea but yeah

#

now punning is basically what we call circumventing type system checks

#

you tell the compiler that from now on it should treat it as if it was float from the beginning

#

it's nothing more

#

just circumventing these type safety checks

heavy basalt
limpid elm
#

to store an address and tells the compiler to interpret the value as float

#

even if it isn't

heavy basalt
#

ok

#

I can see so many useful way to use this

limpid elm
#

it's nothing but circumventing the process

#

now to your old example

#

if you will

#

how come you could cast entity to int

#

you remember the definition of the struct, it was two integers

#

in memory it's just that, two integers, but considering it's a complex type

#

with possibly many other types of variables

heavy basalt
#

address still exist, it's just the type that change?

limpid elm
#

addresses don't have types, it's only for us and the compiler to interpret the value under the memory address

#

memory address is always an integer (under the hood), big enough to address entire memory space

#

address is just index of the memory

#

nothing more

heavy basalt
limpid elm
#

it doesn't, we just tell it to interpret the memory by what the type is

heavy basalt
#

does the float "pointer" make it know the type?

limpid elm
#

computer does not know what float is, or integer is

#

it's language construct if anything

heavy basalt
#

even*

limpid elm
#

for us and the compiler to tell the processor how to deal with variable, you see processors work on what we call processor instructions

#

processor instruction tells the processor to which module send the memory

#

and how to operate on it

#

so if you want to substract two floats

#

it sends it to fpu

#

modules just do their thingy on memory

#

they don't care either

#

compiler made sure that floats always go to fpu modules

#

with instruction of the processor

#

but the processor itself doesn't know shit

#

about types

#

it does not care

heavy basalt
#

so it's just the compiler that detects it?

limpid elm
#

yep, and it's also for us

heavy basalt
#

so that it can be put into the right module?

limpid elm
#

to know what we are dealing with

#

yep

#

and for us obviously

#

so when you type pun you are basically telling compiler to pretend

#

and if you used these float* to calculate on integers

#

it would use fpu

heavy basalt
#

wait

limpid elm
#

because you told it, it's a pointer to float

heavy basalt
#

just going to make sure, the address is saved but the type is switched right?

#

wait

limpid elm
#

the interpretation is, int a is still int a, but we pretend it's float a

#

and we can only pretend while using float*

heavy basalt
#

so it's just a pretend, like a reference but it's just pretending to be a float?

limpid elm
#

once we start dealing with a itself it's an int so we deal with an int

heavy basalt
limpid elm
#

yeah, you would tell the compiler that it's dealing with floating point number under the address

heavy basalt
#

how does the address uhh know it's type and then "pretend" to be a float

#

is it bc the pointer

#

that it knows the type

limpid elm
#

no the address doesn't know shit, again it's just an address, a number, an index of memory

#

the language deals with types

heavy basalt
#

then how do u pretend the type

#

if the address doesn't know stuff

limpid elm
#

compiler, when compilling stores the types and names

#

so when it sees

#

a_ptr_float or whatnot, it can check it's type anytime

heavy basalt
#

wait

limpid elm
#

and since you made it think that it's a pointer to float it starts operating on it as it would be float

heavy basalt
#

ohh

#

so basically like

#

it just doesn't care

#

what type is it

limpid elm
#

yeah

#

you told it to think of it as float

#

and it did

heavy basalt
#

the address doesn't know it's type, like it's not declared yet bc its an address

#

so u can like customize it's type by doing that?

#

but why pointer tho? is it because it's an address

limpid elm
#

I mean it's never declared, the types aren't stored in memory at all whatsoever, once the program is compiled it's just values and addresses

heavy basalt
#

ohhhhhh

limpid elm
#

you know MS Excel?

heavy basalt
#

I get it now

#

yeah I get it now

#

address was never declared yeah I got it now

#

wait why are u a beginner and teach well

limpid elm
#

types tell us what we are dealing with, and types tell the compiler what processor instructions to use to operate on them

heavy basalt
limpid elm
#

because there are only two things that deal with memory adresses per se language logic wise

#

references (once set you cannot change what it refers to)

#

and pointers, these can change what they point to

#

pointers are more risky but more versatile

#

they allow for more

#

but they make you responsible for possible errors

heavy basalt
limpid elm
#

you made it to point to specific memory address ergo &a memory adress of a and treat it as if under this memory address was float

heavy basalt
#

what is ergo

limpid elm
#

in other words

heavy basalt
limpid elm
#

is what I wanted to say

#

you point to just memory address

#

there's no float memory address or int memory address

#

it's just an address

#

as far as we are concerned

#

you could just do this

#

float* ptr = 0x7777

#

address is an integer like I said

#

thing is you decided to use address of a

#

by using &a

#

and you told the compiler to interpret it as float

#

regardless of what memory was under the address

#

the compiler will start treating memory address &a like it was a memory storing a float

heavy basalt
limpid elm
#

it will do nothing to value at memory adress of 0x7777, I mean you did not do anything yet but store the address and you also told the compiler that every time you access the value under memory adress of 0x7777 through pointer ptr, then it should use floating point processor instructions

#

perhaps you need a demonstration, give me a second

#

ask questions in the meantime if you have any

heavy basalt
#

i gtg ill chat with u later ok

heavy basalt
limpid elm
#
#include <iostream>

int main() {
    int a = 14;
    std::cout << "a.address = " << &a << "\ta.value = " << a << "\n";

    // when &a is accessed through
    // fptr_a, treat memory of adress &a
    // as a floating point number
    float* fptr_a = (float*)&a;
    std::cout << "a.address = " << fptr_a << "\ta.value = " << *fptr_a << "\n";
    *fptr_a = 14.0f; // float have different representation in memory
    std::cout << "a.address = " << fptr_a << "\ta.value = " << *fptr_a << "\n";

    std::cout << "a.address = " << &a << "\ta.value = " << a << "\n";
    return 0;
}
void geyserBOT
#
Program Output
a.address = 0x7ffe1a806604a.value = 14
a.address = 0x7ffe1a806604a.value = 1.96182e-44
a.address = 0x7ffe1a806604a.value = 14
a.address = 0x7ffe1a806604a.value = 1096810496
limpid elm
#

@heavy basalt see how I used both variables in the code, and how there were interpreted

#

just in case *ptr is used to dereference the pointer, meaning access the value under the memory adress the pointer is pointing to with the interpretation of pointer type

#

since I pointer to &a with pointer to type float, every operation on &a when accessing this adress through float* was treated like operation on float

#

that's why 14 assigned as int has this weird value when displayed as float

#

because they have different representation

limpid elm
#

example

#

you know std::cout right?

heavy basalt
#

yeah

limpid elm
#

then I think you can understand whole example

heavy basalt
limpid elm
#

it will read from the address to copy the value under it yes

heavy basalt
#

ohh ok

limpid elm
#

types also informs it how many bytes to read

#

so if you let's say

#

pointer with double* and double is size of 8b

#

then you would possibly access memory not available to your program

#

that usually results in your program crashing

#

or you would get some garbage value assuming that you could access the memory

heavy basalt
limpid elm
#

ah sure ye

#

here you go

heavy basalt
#

thx

heavy basalt
#

how does that happen

#

i still don't understand

#

how did it get a weird number

limpid elm
#

well

#

what do you think, just by looking at the code

#

what did I do to &a with my new pointer?

heavy basalt
#

u pretend it to be a float

#

but I don't understand why is the value so weird

limpid elm
#

recall what I said about differences between int and float

#

that will tell you

#

it won't explain exactly why the value is what it is, but it will tell you why it did not display 14 again

heavy basalt
#

is it because the byte thingy

limpid elm
#

it has different representation*, I can explain somewhat if you want

heavy basalt
#

Sure

limpid elm
#

Think about it, when you have int you never worry about fractional values right? There's no such thing for integer like 100.12

#

In case of float and double we do deal with fractional values

#

So how do we store the information as to where that . is?

heavy basalt
#

from the type float?

limpid elm
#

We still want to store huge range of numbers in it, but we also need to store where . is

heavy basalt
#

oh is it because it's an int, and int doesn't have that . so like it confuse the thing and generate random number?

limpid elm
#

no

#

no confusion

#

just different interpretation of memory

heavy basalt
#

oh ok

limpid elm
#

it doesn't care, it just treated it like an int/float depending on what you told it to

#

so mathematicans decided at some point

#

to create special representation for floating point numbers

#

so they can still use the same memory size

#

and let us store relatively close range of values

#

float also takes 4bytes but does not let us store

#

maximum that int can, we do gain the info about where to place . though

#

that's why computer cannot read and treat them the same way

#

unless you told it to

heavy basalt
#

I get it now

limpid elm
#

so when I told it to print &a as a float

#

it converted this memory to text

#

as it would convert the float to text

#

or otherwise if I told it to treat it as int

#

methods for converting numbers to test vary because of it too

#

ok so there's that struct of yours

#

it's just two integers

#

so we store just that in theory

#

but there's another thing one would have to mention

#

depending on architecture

#

it's easier for processor to access memory in a certain way

#

and compiler tries to optimize things so it's easier for it

#

to read and write to memory

#

because of this structures don't necessarly have size of just the types

#

combined

#

there are also things called padding and memory alignment

#

that might be involved, basically it's an empty space made between or after members of the data structure

#

so it's easier for the processor to grab the variables

#

remember how I said that adress is really an integer under the hood and one big enough to adress entire memory address space?

#

well on x64 it's 8bytes, that's the size you need to save any memory address

heavy basalt
#

nah I forgot

#

ok

limpid elm
#

and so pointers have the size of 8bytes, exactly to be able to store every address

heavy basalt
#

how are u a beginner, someone promote u bruh

limpid elm
#

and so to account for easy address manipulation

#

compiler makes sure

#

that processor can go by 8 bytes

heavy basalt
#

I get it now

limpid elm
#

I will give just one example of that, and you digest the knowledge

heavy basalt
#

ok

#

just screenshot it and send bc im on mobile

limpid elm
#

Also, compiler decides how to align and in what order to place the variables, so you are not guaranteed to have &k == &k.a.
Usually that's the case though, for C/C++ compilers at least

#

if you consider issue to be solved, do post !solved or was it !close[d]?

#

And reminder, I used C style punning only cause you were familiar with it, and it's simpler to digest

#

for C++ learn about reinterpret_cast and static_cast

#

for this issue, the first is what you need

heavy basalt
#

ok

#

i get it now

#

are u a secret advanced c++ person disguising as a beginner

#

any all solved I'ma do !solved

#

!solved

magic galeBOT
#

Thank you and let us know if you have any more questions!

This thread is now set to auto-hide after an hour of inactivity

sinful kernel
versed brook