Bit Fields in C. What are they, and how do I use them?

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
welcome back everyone to a video about a computing topic that a lot of students beginning programmers may not get in class of course all source code for this video is available through patreon a big thanks to all of you that support the channel in various ways if you like what you see here please consider giving this video a like subscribe if you want to make sure you don't miss the next one and of course if there's a topic you'd like to see in a future video be sure to comment down below for this video I'm using C but the topics we're talking about translate really well into just about any programming language either natively or through some kind of add-on or library ok so computer data is binary I know this you know this my mom and dad who don't write computer software they know this but even we as programmers that are dealing with these binary data all the time usually don't interact directly with the ones and zeros for example if I declare an int on my machine that integer is going to be 2 or 4 bytes that's a bunch of ones and zeros but normally I just treat it like it's a single numeric value when I assign this into a new value it's going to change all 32 bits all at once but today we're going to do things a little bit different as we look at bit fields we're actually going to access individual bits and those bits are going to have meaning and the main reason for this is usually space we're either trying to represent data very compactly maybe we have a lot of data and we're trying to limit how much memory we're using maybe we're sending data over the network and we really want to pack as much information as possible into a few number of bytes because we've got limitations on the packet size that we can send but either way when we're trying to pack as much information into a small space as we can that's where bit fields come in so a big field is just a series of bits where individual bits mean different things and could be individual bits or clusters of bits but single bits or chunks of bits are meaning something and you're going to see bit fields show up in three different scenarios that I'm going to talk about today the first is for representing options flags or attributes that you're passing to a function consider the open function the one we use to open files so we give it a pass to the file we want to open and then we give it a bunch of flags and you'll notice the flags argument is just an integer but when you see examples of how open is used you're gonna see something like this and you might be wondering how does bitwise or in these constants together you might just be thinking this is a really strange way to do this except it's really not you see what's going on is that the flags parameter is a bit field it's an int so that's 32 bits on my machine but each of those 32 bits corresponds to one of these different options well that's of course assuming that there are 32 options it's actually likely that some of them aren't used here so when I or in the read-only option what that does is that sets the bit that corresponds to the read-only flag to one ok so setting that bit to 1 means I want to open this in read-only mode so let's see how this would work in an example of our own so say I have a function that logs messages to a file a lot of software out there uses log files of servers you see this a lot and these log files give you a record of what happens so that you can go back and figure out why stuff broke when things eventually go wrong so this log message function logs some message that I give it along with a bunch of other information so we prints out a counter the date and time of the message and the user's login ID and of course the message that we want to log to the file and down here in main I'm just testing things out but what if I don't always want to print out all of this stuff maybe I'm making a library with a generic function here and I want to get my users lots of options but I don't want to force them to use all of the options all the time I want to leave that up to them so let's make another argument to my function that's going to give us some options and for this of course because it's the topic of our video today we're going to use a bit field notice that I'm using a u int 8 underscore t which is just an 8-bit unsigned integer I have a video on standard intz if you want to check it out I'll put a link in the description but this variable gives me 8 bits to work with and that's going to be enough for me since I don't plan on having more than 8 different options for this function now let's define our options let's give the users the option to include the time the date the user login ID and the counter ok and I'm going to define each of these values as an 8-bit sequence with a single one and all the rests set to 0 okay so a 1 in the first bit the zeroth bit is going to mean include the time a 0 will mean don't include the time a 1 in the next bit position means include the date and so forth ok so now I can come down here check these bits to see if that option has been selected for this I'm going to use the bitwise and operator which is going to go through each bit position and return a one if both bits in that position are one so in this case we will only have a one in that position if it was previously said and we'll do this with count and a date and the time and the username and that's it now we need to come down into main and add the options to our log function calls for the first one let's just not passing any options but a second let's do the user name and the date but the third will request the time the username and the count and for the last one we'll just display the count and now if we open our terminal and compile it and run it you notice that it works the log messages are appearing and the options that we requested are being included the great thing about bid fields here is that it allows us to easily mix multiple options and this doesn't just have to happen when I call the function I can also come up here and define some other options that are combinations of the individual options that I have already defined like for example I can make one that turns on all of the options in a single super option or maybe I want people to be able to request a pair of options like date and time which often go hand in hand so these hybrid combination options are going to work just as if we combined the original options with the bitwise or operator just to make sure let's test it down in Maine and sure enough you can see that it works just how we want it to and so this used to specify a collection of options or flags this is an area number one and it's one you're going to see all the time in a bunch of different sea api's and libraries scenario number two is when you want numerical values like integers but you don't want to spend a lot of space on them maybe for example you're just trying to store a person's grade in school and you know that it's always going to be a number between 0 and 12 and it seems really wasteful to use 32 bits to store a number that you know won't ever use most of those bits so just to show you how this works I'm going to define a struct with three counters in it the first will use only two bits and the second uses four and the third uses six so otherwise these counters are identical they're just different on how many bits they use and how much space they take out now let's make a loop that's going to go through and count up each of these counters and then I'm going to print out the values and this I think will allow you to see this sort of bit field in action okay so let's declare our counters and let's initialize each counter to zero and then each time through the list I'm going to increment all three counters the little the medium the large and then we'll print out the values each time through the loop that way we can see what's going on and let's compile it and it seems that I can't spell little now let's try again let's compile it and run it and we get a bunch of numbers let's go back up to the top of the output and you'll notice that the negative numbers here initially might seem a little confusing to some of you but remember that we are dealing with signed ins so because it's assigned int the most significant bit in the binary number determines the sign so if you keep incrementing any integer it will eventually become negative and that's what's happening here the first one becomes negative really quick because it only has two bits so it can only store four different values so now say we want to stick with non-negative values we can make these all unsigned and I'm going to change in the struct as well and now if I compile it and run it we see the same thing but they're all positive so you notice that we count up to the largest integer that can be represented with two four or six bits and then it wraps back to zero now the point of all this was to save space right so just to make sure that we're actually saving space I'm also going to go and print out the size of the struct just to make sure that we're actually saving space with two four and six bits that's twelve bits total I should only need about two bytes to represent that right and if I compile it oops sizeof returns an unsigned long okay now we can compile it and run it and it's using four bytes which is a bit frustrating if my goal was to cram as much information into the smallest space possible I was not successful so so why why did this happen well the reason is the compiler thinks the program will run faster if it aligns the members of my struct along certain boundaries and you know it's probably right if all you care about is speed just let the compiler do its thing let the compiler lay things out in memory the way that it wants to but what if I do really want to cram all these values into two bytes what if I do really want to save space even if it means that my code runs slightly more slowly because I want to use less memory well in that case I can just tell the compiler to pack the struct like this here we're basically just saying to the compiler when you lay this one out in memory pack it all together keep everything very tight write one after the other and now if you compile it and run it you'll notice that it is only taking up two bytes so that's scenario number two the third bit field scenario I want to talk about is when you want your bit field to act like an array of bits you don't have a name for each bit position you just want to treat this 64 bit unsigned integer as an array of 64 bits hey it's an array of ones and zeros now it would be awesome if we could just do something like this and declare an array of bits trust me many a programmer has dreamed this dream but I'm sorry the language isn't going to do this for us today so instead I'm going to define a few macros one is to set a bit to one I'm writing out all the bytes in hex here just to remind you that there are eight of them but I basically just shift a one to the left end places and then or that with the bit field second I want to have a macro that will clear a bit back to zero we do this by shifting a one left end positions in the same way we did before but this time we take the complement basically turning the ones to zeros and the zeros to one and then we and that with the bit field and that will leave all the other positions alone and just turn the bit we want to a zero okay finally let's make a macro that will test and see if a particular bit was set for this I'm going to shift the bit field right end positions and end it with one that's going to remove everything except for the position that we are interested in and that will remove everything except the position that we are interested in and so it'll be a 1 if it's said it'll be a 0 if it's cleared so let's try it out let's set a few bits that's clear a bit as well just to make sure that's working now let's go through our array and use our is bit set macro to determine whether or not each bit is set and we'll print out a plus sign if it's set and a period if it's not and of course we need a new line at the end and now let's go to our terminal we'll compile it and run it and you can see that the bits we set our set and the one we cleared is not set and if I change the pattern set another bit and compile and run you notice that the pattern is updated appropriately so that's it for today I hope this helps you better understand bit fields to know what they are and how you can use them in a variety of scenarios thanks for watching subscribe if you don't want to miss the next video and until then I'll see you later
Info
Channel: Jacob Sorber
Views: 25,336
Rating: 4.9622345 out of 5
Keywords: bit fields in c, bit fields, c bitfields, bitfield in c, binary, tutorial, c bit fields, c tutorial, c language, c programming, bits, bit masks, binary fields, how to use less than a byte, bit field, structures in c, bit (unit of data size), bit field in c, bit fields in c language, bit manipulation, bit manipulations, bit masking, bit twiddling, c (programming language)
Id: aMAM5vL7wTs
Channel Id: undefined
Length: 13min 26sec (806 seconds)
Published: Mon Mar 09 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.