A passer-by note : in C, you are only technically suppesed to do bitwise operations on unsigned integer types. Signed integer type behavior is signedness implementation specific. Most coding standards will shed a tear if you do this. They will even make you specifically declare your constants as unsigned. I personally allways fall back to unsigned types and use signed types only when necessary. Just saves me a lot of trouble in general.
@esdel Жыл бұрын
I think with C23 negative number representation gets standardized to 2s-complement and with that a lot of signed value behavior should get standardized as well, but I might be wrong.
@anon_y_mousse Жыл бұрын
@@esdel I sure hope you're wrong. That would reduce C's portability because then the behavior will have to be explicitly redefined for 1's complement machines.
@xhivo97 Жыл бұрын
@@anon_y_mousse 2's complement is in C23. 1's complement machines exist? (I realize you might have been sarcastic on that one lol)
@anon_y_mousse Жыл бұрын
@@xhivo97 They're old and rare, but they do exist. It's just that this will be a constant craw in my beak when I try to tout the portability of C and proponents of every other language will point this out with glee even though C will still compile for such computers and many more that their language of choice won't work on and it'll irritate me. It's tough being one of a small handfuls of C proponents. Only makes it worse that now I hear they're adding constexpr to C. If they're just going to copy every C++ feature then I can't finish my own language fast enough.
@xhivo97 Жыл бұрын
@@anon_y_mousse IDK what to tell, other than use an older compiler or -std=c89 if you must... Could you explain _why_ those are bad? Backwards compatibility with archaic machines is a not a good reason to hold on from having good features. I don't mean to be rude, but after some light searching I couldn't find any such machine, do you mind naming one for my own curiosity? I would be more concerned about potential UB when subtracting when on 2's complement. Like it or not the majority of C's issues could be made less bad with language features that play well with static analyzers and runtime sanitizers; VLA syntax which has been a (optional?) thing since c99 gives you a bit better bounds checking when using a sanitizer, constexpr would also provide some static checking benefits I imagine but I've never used such a feature so am not quite sure. But I'm sure the C standard is in good hands and you gotta move on with the times at some point.
@cusematt23 Жыл бұрын
I’ve watched like 50 of your videos this week. Great stuff.
Жыл бұрын
Would be interesting what the compiler does. If I write x & (0x1 n) & 0x1 with the example above.
@metroid031993 Жыл бұрын
it depends on the compiler, really. I've seen both happen, in different scenarios with the same compiler even.
@edgarbonet1 Жыл бұрын
Any half-decent compiler knows how to do constant folding. Thus, if n is a compile-time constant, 0x1
@AkiiiMatcha12 күн бұрын
Your videos are super super helpful and I really appreciate the effort and planning that you put into them! Thank you for this high quality content ❤
@hampus23 Жыл бұрын
Keep up the excellent work with your educational content! 🙌
@osamaadil231 Жыл бұрын
Very informative! Keep up the good work ❤
@deepakr8261 Жыл бұрын
How about the union method Dr Sorber? So assume the example of a 32 bit register with each bit having specific purposes. So you can define something as below: union { uint32_t num; struct { uint8_t a:1; // bit indicates something else uint8_t b:1; //1 bit indicating something uint8_t c:2; //2 bits indicating something ... }fields; }reg; So say you read the 32 bit register into num as reg.num = (volatile uint32_t *) (address) and then to access individual bits you can simply do reg.fields.a or reg.fields.b etc
@edgarbonet1 Жыл бұрын
The order of bit fields is not specified by the C standard. This method may work on one compiler, fail on another one, and break on the next version of the compiler where it used to work.
@deepakr8261 Жыл бұрын
@@edgarbonet1 From the c99 standard "An implementation may allocate any addressable storage unit large enough to hold a bit-field. If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed into adjacent bits of the same unit." In this case, the storage unit is uint32_t as set by the union
@edgarbonet1 Жыл бұрын
@@deepakr8261 The bit fields are indeed adjacent. The order of allocation, however, is implementation defined. You could expect a consistent order only if the platform's ABI specifies it.
@godnyx117 Жыл бұрын
Top tier content! You are a true OG!
@paulmichaud3230Ай бұрын
Something interesting that I encountered with this code: template void printBinary(T n) { const size_t BYTE = 8; const size_t numBits = sizeof(n) * BYTE; for(int position = numBits - 1; position >= 0; --position) { printf("%d", BITVALUE(n, position)); } } Calling it with uint8_t has undefined behavior because uint8_t is typically treated as a char type (?). I also get weird behavior if printBinary is called with a uint size that has been static_cast from an int. It could be the template type, but seem likely to be the sizeof operator.
@GAMarine1373 ай бұрын
Thanks for the video
@Psychx_11 ай бұрын
What's the advantage/disadvantage of using defines to create the bitmasks? Can't that also be done using an enum?
@savantshuia Жыл бұрын
What's the typeface you've used for the text on screen?
@shoyur Жыл бұрын
I made a function to return a string of that binary, and the result was always empty, cause it was composing the string of only 0 or 1 as int, so empty characters, took me 15 min to find the bug. It made me learn that you can convert a 0 or 1 (as an int) to a char very easily by adding 48 cause 48+0=48 which is '0' in ASCII and 48+1=49 which is '1' in ASCII.
@edgarbonet1 Жыл бұрын
Don't add 48, add '0'. Yes, “'0'” is just another way of writing “48”, but writing it as a character constant makes the programmer's intent clearer, which is important in the long run.
@bozhidarivaylov5611 Жыл бұрын
wow that was a goood one. THANKS!!!!
@edgeeffect Жыл бұрын
Considering that most ISAs have a simple bit set/reset instruction... it always annoys me how complex and unintuitive it is in nearly all high level languages... but I AM a huge assembly language enthusiast and snob.
@edgarbonet1 Жыл бұрын
The AVR instruction set has the instructions “Set Bits in Register” and “Clear Bits in Register”. However, if you look at their binary encodings, you realize that these are merely aliases for “Logical OR with Immediate” and “Logical AND with Immediate”. These aliases are just hiding the bitwise boolean operations in the same manner as the macro used in this video.
@TreeLuvBurdpu Жыл бұрын
Do you recommend that method of looping from the end, rather than starting at the end and then i--?
@jarlfenrir Жыл бұрын
my guess before watching: bit shift so your desired bit is at 0th position, AND with 1 and then you can check if your value is 0 or 1?
@etiennepretorius1993 Жыл бұрын
What about a bit field in a struct?
@bloom945 Жыл бұрын
I like this a lot more since you can make it super clear what everything is. For the same reason I tend to prefer enums over macros for bitflags.
@rexjuggler19 Жыл бұрын
You beat me to it. You can address bits using a structure which might be a bit easier. struct { unsigned readonly : 1; unsigned hidden : 1; unsigned system : 1; unsigned volumelabel : 1; unsigned subdirectory : 1; unsigned archive : 1; unsigned bitSix : 1; unsigned bitSeven : 1; } fatByte fatByte.readonly = 1 fatByte.hidden = 1 fatByte.system = 0 fatByte.volumelabel = 0 fatByte.subdirectory = 1 fatByte.archive = 0 A good example of using bit fields would be for GPIO access on devices like raspberry Pis to activate LEDs etc.
@hoffiee123 Жыл бұрын
@@rexjuggler19 I agree, and that together with unions you can easily pass it between interfaces which doesn't use bit fields without having to do some type casting
@gosnooky Жыл бұрын
This is the way
@maxaafbackname5562 Жыл бұрын
The problem with bitfields is that the order is undefined. As in that is undefined if the first bit is bit zero or not
@bsdooby Жыл бұрын
A bit of bikesheding here: why are you (still) using `void` in an otherwise empty parameter list (here of the main function)?
@JacobSorber Жыл бұрын
old habits? 🤔
@bsdooby Жыл бұрын
@@JacobSorber No offense intended, I was just curious. Thx for your reply!
@JacobSorber Жыл бұрын
@@bsdooby none taken. it's a good reminder.
@baguettedad Жыл бұрын
But instead of a macro, wouldn't it be easier to use enums for the same purpose? Great video btw!
@MechPaul Жыл бұрын
Why not both?
@baguettedad Жыл бұрын
@@MechPaul macros can be a pain to debug
@maxaafbackname5562 Жыл бұрын
You mean to define the bit constants?
@ゾカリクゾ Жыл бұрын
not really, since the idea of bitfields is encompassing 8 independent properties of something. there are 2^8 states possible, which you would have to define individually as an enum. It's just not the appropiate structure.
@rustycherkas8229 Жыл бұрын
@@ゾカリクゾ enum { foo = 0x1, bar = 0x2, gib = 0x4, gab = 0x8, bob = 0x10..., comboX = foo | bar, comboY = foo | gib | gab, }; Simply specifying tokens and their values. One doesn't need to fill in 256 (or more) using the default 'auto increment' feature of enum's.
@artem.pirkhal Жыл бұрын
Hi Jacob. Many thanks for your work. Could you explain, how does delete operator knows exactly how many memory we allocated by new operator, and how we can repeat this logic for malloc/free functions in C? I tried to get shifted pointer to sizeof(size_t) bytes before actual pointer and find that we have strange number which is pretty much allows us to know how big chunk was allocated but for my machine it was never lower than 33 bytes even if I requested single sizeof(int ) memory. So I have question: why this allocated block is always has size so much bigger than was requested and why this size always follows condition (size % 2 == 1)? I mean why this lower bit is always(?) equals 1. Short code example below void *p = malloc(sizeof(void)); size_t *ph = (size_t *)p - 1; printf("size: %lu ", *ph);
@DiThi Жыл бұрын
As far as I know, there's no official way in C or C++ to get the amount of allocated memory. Each standard library in each OS can do it a different way. What you do here is undefined behaviour (i.e. it may work for you but it can probably fail for someone else). If you want to ensure you always know the allocated length, you have to write replacements of malloc and free yourself which allocate one extra size_t where you store the length, where you return the pointer next to this number, and where you calculate the previous one before calling the actual free.
@artem.pirkhal Жыл бұрын
@@DiThi Yep. I know it. But I still want to know why memory header ((size_t *)ptr - 1) contains this weird number 33, 49, 65, 81, 129? For what purpose this lower bit set in 1? Does it means that next 32, 48, 64, 80, 128 bytes was allocated? Then why it doesn't switch to 0 after we free this memory? I just want to know what this header value means. I tried to find this information but I'm still here... I hope you, Or Jacob could help me?
@DiThi Жыл бұрын
@@artem.pirkhal operating systems don't allocate ranges of bytes, they allocate entire pages (in most systems that's 4kb). So malloc and friends keep track of used memory within those pages in some other way, like storing the size of the allocated memory at the beginning of each chunk. I just checked that code in my system (linux) and I get the same result, some odd number multiple of 16 + 16 + 1. My guess is that it's actually not the size, but a combination of the size and some flags. That extra 1 is probably some flag with a different meaning. Since it's always aligned to 16 bytes, it doesn't need the lower 4 bits, so it's zeroed out and used for other purposes. I accidentally corroborated this by adding more parameters than arguments to printf, which prints internal CPU registers and one of them is the length without the extra +1. It's probably not set to zero because it's likely keeping small freed buffers around to give when requesting another malloc, so it doesn't waste time calculating stuff.
@artem.pirkhal Жыл бұрын
@@DiThi Make sense. But using overloading of new/delete we are able to track memory allocation in C++. Sad that we don't have this abilities in C. Only by making custom allocation/freeing macros or function overloading. Interesting to know, how that implemented in C++
@DiThi Жыл бұрын
@@artem.pirkhal We can certainly do that in C as well. There's many custom allocators, but the simplest way to do it in your application is just by doing e.g. #define malloc(x) my_malloc(x), and from your malloc you can call the original one. Of course the macros must either come after their definition or not be present at all in its own .c file, otherwise you can't call the original malloc. Unless you use their alternate names. E.g. in linux glibc we have __glibc_malloc and __glibc_free.
@matiasm.3124 Жыл бұрын
Nice video as always..but i don't get why you have to finish with & 0x1 in the printf or the macro when you do the bitwise..
@marwan7614 Жыл бұрын
Let's say you have : 00001010 ^ To check the second bit you first shift so to the right by one so >> 1 then it becomes: 00000101 ^ But then you have an extra bit so to get rid of it you do an AND(&) operation so 00000101 & 00000001 = 00000001 Then only the first bit is left if was 0 the the result would be 00000000 Btw 0x1 = 00000001
@matiasm.3124 Жыл бұрын
@@marwan7614 very nice explained.. thanks for your time.
@h_bra Жыл бұрын
Very useful video and good explanation. But i would have liked to get into more detail, for example explain how to change just one bit. Bit still great video and thanks for the content
@pumpkinhead002 Жыл бұрын
To set a bit to 1 you would create a mask of all zero and the bit to set equal to 1. Then you would logically OR "|" the mask with whichever variable that you want to set. If you want to set the bit to 0, then you would invert the mask you made above, such that the but to set is a 0 and the bits you want to keep are 1, then you AND the mask with your variable to set the bit to zero.
@Spielix Жыл бұрын
Creel has a video "Bit Hacks from Beginner to Advanced" with some nice visualizations.
@walkero Жыл бұрын
Great video as always. Thank you
@zacharymiller7573 Жыл бұрын
Which editor do you use for programming?
@frango_molhado Жыл бұрын
The one in the video is VSCode
@luke-v8c Жыл бұрын
Could you make a video about nan in c?
@JacobSorber Жыл бұрын
What about it?
@rian0xFFF Жыл бұрын
Nice
@jarlfenrir Жыл бұрын
When you provided ARCHIVE value, shouldn't it be a 0xA instead of 0x10?
@edgarbonet1 Жыл бұрын
No: - 0xA is decimal 10, binary 1010 - 0x10 is decimal 16, binary 10000.
@jarlfenrir Жыл бұрын
@@edgarbonet1Right, 0xA would set two flags at once. My bad.
@blameItleaveit Жыл бұрын
It would be great if we could purchase your C course from somewhere instead of juggling from youtube videos
@zxuiji Жыл бұрын
Shouldn't teach people to hard code values like 8 bits, we have CHAR_BIT, should use every time to teach people to be in the habit of using adaptable macros instead of hard coded values. The people who learnt to hard code 8 bits as the length of bytes will surely in the future encounter situations where they will have to go through their whole code base replacing that value because of that bad assumption (granted 9 times outa 10 it will be because of old systems that they need to but there's surely research systems etc that use bigger values too)
@casperes0912 Жыл бұрын
Find me a machine made after the 486 where the value is different
@anon_y_mousse Жыл бұрын
@@casperes0912 Does that stop the older machines from existing?
@zxuiji Жыл бұрын
@@casperes0912 I'm not a researcher (well not a professional one anyways) so I don't know what machines there are with it different but then there are dumbass data modals like SILP64, what's to stop some research facility ordering a custom computer where it's different? What's to stop them then using any of the software available to the public on said machine? The art of programming is to throw out every assumption you can, no ifs, buts or whats about it, just throw them out.
@Hauketal Жыл бұрын
@@casperes0912Lots of signal processing CPUs aka DSP are not byte oriented. They often have 12 or 16 as CHAR_BIT. And yes, even new ones.
@casperes0912 Жыл бұрын
I’ll use avx without any runtime checks
@itsdrdy5551 Жыл бұрын
instead of 0x just use 0b
@rammrras9683 Жыл бұрын
How to toggle a single bit ?
@johngangemi13619 ай бұрын
Use the C bitwise NOT operator ~
@JacksonBockus7 ай бұрын
@@johngangemi1361No, use ^ (xor)
@mowinckel10 Жыл бұрын
A thing I like to do, is instead of writing the bitmasks in HEX, I often write them in binary. Basically anytime if I feel the need to comment the binary after
@pumpkinhead002 Жыл бұрын
C doesn't support binary literals. That is a GCC implementation.
@ajtan2607 Жыл бұрын
@@pumpkinhead002 C23 includes binary literals that works similarly to the one in C++. Apostrophes (') can also be used as digit separators. Here's an example: 0b'0000'0000'0000'0000
@Spielix Жыл бұрын
And especially if you are using 64 bit types, writing out all bits on their own will be less useful IMO because counting the positions is harder than learning how to read hex.
@thebirdhasbeencharged Жыл бұрын
Drop the shirt link
@lehisluguer93004 ай бұрын
its a little BIT faster this way
@grimvian Жыл бұрын
Not many youtubers are making C videos these days, so I really, really appreciate you are spending time to make them. However for a C learner like me, the videos are made in a way that are very zappy to me and the you are talking very, very fast. But maybe the audience you aim are more experienced and much better to English, than me. From a pedagogical view, I think, there are to much information on the screen. The code is only using about half of the screen space and the music is just noise and totally irrelevant to me. Prerequisites knowledge for the video will also be very fine. The best learning videos for me, just start immediately.
@TreeLuvBurdpu Жыл бұрын
I agree mostly, but these are level 200 and expect some familiarity. He is publishing for his students and similar. There are other introductory C Lang videos available.
@grimvian Жыл бұрын
@@TreeLuvBurdpu We all have our preferences and I consider myself at a medium level. The best C Teacher I know is Kris Jordan: kzbin.info/aero/PLKUb7MEve0TjHQSKUWChAWyJPCpYMRovO
@grimvian Жыл бұрын
@@TreeLuvBurdpu More than two hours of exellent C talk with no noice and from level 0 to at least level 200, I think. How I program C with Eskild Steeberg: kzbin.info/www/bejne/amWWhoGbfNd5pa8
@edgarbonet1 Жыл бұрын
As a non-native English speaker, I do find the speech a bit fast at times. However, his articulation is very clear, so it is easy to follow nevertheless. You may try slowing down the video if you are struggling.
@grimvian Жыл бұрын
@@edgarbonet1 I agree, but I also oppose irrelevant noises e.g. music and fancy video editing. Also I don't need to know, which IDE that is used, but just the code.
@danielrhouck Жыл бұрын
In many cases it’s more accurate to say computers represent everything in sexaquinquabicentesrmal, not binary. But nobody wants to say that partly because *simplified* computers do use binary and partly because, well, do *you* want to regularly pronounce that?
@maxaafbackname5562 Жыл бұрын
No idea what numberingsystem you are referring to. Google can't find anything about it. Is it something like 64? In some sense you are correct, there are 64 wordsizes, but also other wordsizes, like 32 or even not a power of two. So saying that computers are "that" is already incorrect. But a "computer" can do more than operating on a whole word, like the arithmetic instructions. Enough instructions operatate on a single bit or on separate bits in a word. Further more: at the hardware level, only two levels are used. These levels are encoded as 0 and 1. Another way to say that computers use binary.
@danielrhouck Жыл бұрын
@@maxaafbackname5562 Base 256. Pretty much everything operates on a byte at a time and we have byte-addressable RAM not bit-addressable RAM.
@HansLemurson Жыл бұрын
It's a good thing that bases that are powers of 2 are trivial to convert between! Imagine dealing with base 256, but you have to use a unique symbol for each value...
@danielrhouck Жыл бұрын
@@HansLemurson Yeah, often binary is easier to work with because of that. Just it sometimes helps to think of what the computer is doing as operating on a byte at a time.
@HansLemurson Жыл бұрын
@@danielrhouck I like how Hexadecimal strikes a balance between not having to use too many digits, but also not having too many distinct values. 16 values is easy to wrap your brain around. How computers actually process the data though can vary from machine to machine. I remember building a redstone calculator in minecraft using comparators which was actually _natively_ hexadecimal, since there are 16 different signal strength values. In modern electronic computers, memory-access is byte-aligned, but data is read into the processor in multi-byte words, so when you just want to look at a single byte you have to load 4, and then ignore 3 of them.
@hansibull Жыл бұрын
I would usually do [sharp]define BITVALUE(X, N) !!((X) & 1
@TheMeaningofHaste Жыл бұрын
Can combine the #defines like this? -> READONLY | HIDDEN
@maxaafbackname5562 Жыл бұрын
Yes, because there are no overlapping bits in the definitions.