C++ Casting - Part 5 - reinterpret_cast | Modern Cpp Series Ep. 97

Mike Shah3,119 words

Full Transcript

hey what's going on folks it's Mike here and welcome to the next lesson our modern C plus plus Series in this lesson we're going to be talking about casting continuing our discussion this time talking about reinterpret cast so as you recall we've talked about staticast and dynamic cast in previous videos so make sure you check those out but with that said let's go ahead and see what reinterpret cast is all about here so our favorite website CPP reference here let's just go ahead to the search bar search for reinterpret cast first listing here and here we go so you can read this and read through some of the examples here but the real important part to understand about reinterpret cast is it's one of the last casts that is tried when we're trying to cast some data type again the advantage of C plus 11 is where explicitly listing out the type of cast that we are attempting or intending to do the C style casts again just sort of try something until it works anyways in the C plus plus compiler and depending how we're using those C style casts we might just be treating a certain block of data as a set of bits so with that said let's go ahead and look at an example here just to make this a little bit more concrete I'm going to go ahead and bring up my drawing pad here because I think it'll be useful as well so let's just go ahead and start off with a simple example here so I've got something prepared here and it's sort of the classic so what I've got here is pi here 3.14 and treating it just as a floating point value and what I'm going to do here is just do the typical C style cast here so we'll go ahead and see how this works and then I've got the reinterpret cast and I'll go ahead and explain this sort of mess and why there's ampers ends and so on within this so let's go ahead and just compile this and give this a run here see what the results are okay so with our C style cast here at line 21 we get the value 3. now the reinterpret cast we are saying hey let's go ahead and whatever's at this address let's cast it to a int pointer and then we'll de-reference it so that we get a value back so we're literally getting back some integer value or integral value of whatever Pi is or 3.14 F the floating point value represents and then in this case well if I'm just treating the actual bytes here as well a float which we know Pi already is then I'm able to get 3.14 back okay so again just a little bit of a review of what's going on here it appears that the C style cast here was able to find something and in a way it's able to treat the Primitive types and find some implicit conversion that it could do here and just truncate out 0.14 and just somewhere in the hierarchy just say okay yeah point one four we'll get rid of that and just keep the integral part no problem okay so again the C style cast here is going through some sort of hierarchy here maybe starting with static cast first and saying hey can I do that if it can't then maybe it's trying uh Dynamic cast or maybe if it's just one of the Primitive types again it's just going down this hierarchy until eventually one of the last steps is reinterpret uh cast here that's going to try but it looks like it found something that worked well enough and again just said hey treat this as three we know how to uh do that uh so that that worked there okay but again at this step here at 24 we're literally with reinterpret cast saying okay uh just treat this uh address here where Pi lives give me a pointer to it and an INT pointer holds well what it's going to interpret as an integer okay and if I want the actual value back well then I dereference it so let's go ahead and see what this looks like without the uh dereferencing just so you can see what this uh prints out and again we can just go ahead and see well you know nothing super interesting here we are actually getting the address uh here of Pi so let's go ahead and just uh print that out uh just so you know this is super explicit here address of Pi or sometimes I do with the parentheses here and let's go ahead and run it here so again you can see that you know if we're just getting the address of a pointer it doesn't really matter too much but if we're saying hey you know actually dereference this thing but treat it as an integer well whatever 3.14 uh the floating Point representation which again is going to be different than integers is going to give you a somewhat strange value here okay so I'll go ahead and um let me just go ahead and get rid of this line so I think you get the point here that this is sort of maybe not the intended Behavior but in order to make this a little bit more concrete I think it's useful to maybe come up with an example of where should I use reinterpret cast or where could I use it okay so let's go ahead and take a look at another example that I have prepared here for you and what I'm going to do here is I've got this structure here called game State okay now let me go ahead and split my screen here just so you can see what that struct is I'll keep this towards the top here just so you can uh you know get a feel for uh this actual structure here okay and let's go ahead and move my window down here just a little bit here so we can see what I'm going to show you what is going on so this game State structure here is just some structure you can imagine having in a game I'm using a game example because that's what I'm familiar with but really any sort of um you know system where you've got a chunk of memory that you need to write so for instance let's go ahead and just represent game State here and I've got you know four bytes for the level and I'm just going to label four bytes here and the health itself also four bites because it's an integer and maybe the points the player has scored also for bytes and that I've got a bull for the game complete here game complete and up for the boss defeated or maybe some mechanism that's important for you okay one bite one bite the color doesn't matter here just time representing things so anyways this is the actual struct here and it might get padded you know in an extra two bytes if you've been watching this series here there might be two bytes here but you know we don't care about that extra space for now I just want to be explicit that that's there okay so oftentimes what I'm going to want to do in some sort of game or environment is just take this data here and write it out and if I want to be efficient I can just go ahead and write this data out in one right okay uh meaning to say that I don't want to if I'm opening up some file stream here like you might do F stream this is sort of the pseudocode right you might write the Game state DOT level in one go and then you'd write the Game state DOT health in one go Etc I'll move out of the way here but this is really inefficient because I'm doing two rights here and maybe a flush in between to write out that data so I'm going to go ahead and get rid of this so typically we just want to treat this when we're reading in as hey I have this bag of bites here okay this grouping here of uh what's going to be a total of four plus four plus four that's 12 plus 2 more 14 uh bytes of information and I actually know what the structure is right I know this is my sort of file format this is how I'm structuring my data so I can just read this in as one collection of data okay so let's go ahead and set up this game state with a structure here and I've just populated some random values 66 for the level 100 for the health 999 for the points and the game's not complete and the boss hasn't been defeated okay and we can change these values if we want here okay so now I want to allocate the actual memory for this so what I'm going to do here and because a Char is just one byte of information and at compile time I know how big this game state is going to be it's probably going to allocate 16 bytes for me but I'll let the compiler figure that out on this architecture here and I'll just have this structure so this is where I want to store information here okay and now I want to go ahead and just sort of optimally do my one read call so I'm going to write this idea here so the key idea is like we're gonna do one read from disk to get all our data okay and that's the idea here okay that's the simple idea this is a use case where I can think of where you might want to use reinterpret cast otherwise you know I haven't uh used it I can't say I've used it very frequently other than for this uh case here okay so how am I going to load in this data well again let's assume you know we've read in this game State object from disk here okay or maybe we're doing something like a read call in this case I'm just using mem copy which is just going to copy from some Source into destination some number of bytes here okay so I've got our game State object now I've just allocated this on the stack but you could imagine reading it in from a file here and I've populated it into bag of bytes here now again all we know at this point is that we just have a collection of data right this is just one read that populated the structure and now I actually want to do something with it so my options are I could just sort of set up this data in this way and just say okay let's dereference the first uh item here in this bag of bytes and let's go ahead and think about what's going to happen here because again bag of bytes itself is an address it's a Char of some sort so let's go ahead and dereference it and I happen to get B here okay because I have 66 here in my uh level here okay now what is uh 66 well I have my ASCII table here and well 66 if we find it it is in fact the letter B if you can see on this table where I'm waving my cursor okay so why is this important or why am i showing you this well again I'm just interpreting these bytes as characters so you know there happen to be um you know for for an INT on my architecture four bytes of information populated with a 66 but we're just treating it as a Char so what we could do is go ahead and say hey you know don't just um dereference this value in this array here but let's go ahead and treat it instead as a int pointer okay uh so that it's a integer and then dereference that value okay so let's go ahead and try this and this time we get 66 okay so again let me undo this change that might have happened a little bit too fast for folks I get B but again this time if I cast the appropriate type into here then I get well the value that we've populated 66 okay because again remember looking at our structure this is supposed to be a four byte integer here okay so we've got the correct uh piece of information back now this here looks pretty ugly what's going on and if you're just looking at this code online uh 37 here with this cast that's going on this sort of C style cast this works right I'm saying hey interpret this as a integer pointer and then dereference that but it's it's pretty ugly and um again you know um it's unclear uh what exactly our intent is here so that's where I can see reinterpret cast being used I'm going to uncomment this and show you how to read in this data it's a little bit more clear and again if you are say um reading in some data then this can be a little bit more clear here so I've got my bag of bites I want to interpret it as an instar instar in Star Bull and bull and if you look carefully at this this matches the format that I've got here on the right right this was I'm just going to label these int and B for bull here and B for bull uh in our data structures okay uh now you know when looking at this code I feel like I at least have a chance of understanding what's going on it's explicit that there's a cast going on it's not just some you know weird uh pointery reference and again I'm doing the same sort of trick that we learned about before where I have my bag of bites here and now I'm just offsetting from the start here by 4 8 and so on and in fact just to make this code a little bit more uh portable I should do the size of int and maybe you know size of int times two etc etc okay so let's go ahead and run this and see if we're able to get our game State data back and in this case we are let me go ahead and close this window above I think we know our our structure here we're getting 66 199 so that matches here and false and false which is zero and zero let's just go ahead and because zero can be a common thing to show up um in our code and uninitialized memory change these to true and you'll see that we get ones here okay so this is working I feel like I have a chance of this working I feel like it's maybe a little bit more um you know portable in this way of just maintaining the code and that's one of the ideas of reinterpret cast and again this is where I can kind of see myself using this type of thing now another case where you're probably going to have to think about using reinterpret cast is when you're using uh void pointers for instance where you don't know the action troll type that's the other sort of case of hey I just have a collection of bytes here and I need to reinterpret it I think this is a little bit more concrete here and how I might use this sort of thing and have used it so hopefully that was useful to you folks here all right folks I hope that was an interesting lesson I hope that taught you something about reinterpret our cast again it's one of these things where you have to be a little bit careful if you're casting around data a lot but on occasion it really does have a use and it comes in handy as you can see in this this particular case you know if you're just doing one read of information that can save you a lot of processing versus having to read in the data just read it all in at once and then you can reinterpret the bytes and assign things and populate your structures as you need here now before I let you go though I just want to go ahead and show you yeah one more example here um you know in this particular example I showed you just you know reinterpreting the bytes one at a time again this is going to be sort of wasteful um to do this if you have some big data structure and if that data structure is going to change in fact it's probably better just to do something like this so let me go ahead and comment out our code at the top here this printout here and just show you that we can essentially have the same thing if you're reading in a blob of memory again to just say hey you know create this game State object reinterpret it as some game state that has these five fields for our bag of bytes and then if we run this here which I'll go ahead and let me go ahead and save this clear out our terminal run it and again you can see the same values that we had before here so again that's the same idea whether you're doing this uh one at a time you're just saying hey I have this collection of bytes pack it into this structure and just let it work so I hope that helps make things uh concrete before we sign off here and you understand that example so again thank you for your time hope you enjoyed this uh digression into casting and I'll look forward to seeing you in the next lesson make sure you subscribe so you don't miss that make sure you join our community in the description uh below if you want to get into more discussions I'm looking forward to Growing that and with that said I'll look forward to seeing you folks in the next one

Need a transcript for another video?

Get free YouTube transcripts with timestamps, translation, and download options.

Transcript content is sourced from YouTube's auto-generated captions or AI transcription. All video content belongs to the original creators. Terms of Service · DMCA Contact

C++ Casting - Part 5 - reinterpret_cast | Modern Cpp Seri...