How do I access a single bit?

Поділитися
Вставка
  • Опубліковано 26 вер 2024
  • Patreon ➤ / jacobsorber
    Courses ➤ jacobsorber.th...
    Website ➤ www.jacobsorbe...
    ---
    How do I access a single bit? // Bitwise operations can be a bit frustrating for new programmers. This video shows you a few ways to access a single bit, usually within a bitfield or bitvector.
    Related Videos:
    Bit Fields: • Bit Fields in C. What ...
    ***
    Welcome! I post videos that help you learn to program and become a more confident software developer. I cover beginner-to-advanced systems topics ranging from network programming, threads, processes, operating systems, embedded systems and others. My goal is to help you get under-the-hood and better understand how computers work and how you can use them to become stronger students and more capable professional developers.
    About me: I'm a computer scientist, electrical engineer, researcher, and teacher. I specialize in embedded systems, mobile computing, sensor networks, and the Internet of Things. I teach systems and networking courses at Clemson University, where I also lead the PERSIST research lab.
    More about me and what I do:
    www.jacobsorbe...
    people.cs.clem...
    persist.cs.clem...
    To Support the Channel:
    + like, subscribe, spread the word
    + contribute via Patreon --- [ / jacobsorber ]
    Source code is also available to Patreon supporters. --- [jsorber-youtub...]

КОМЕНТАРІ • 124

  • @filips7158
    @filips7158 11 місяців тому +89

    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
      @esdel 11 місяців тому +1

      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
      @anon_y_mousse 11 місяців тому

      @@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
      @xhivo97 11 місяців тому +3

      @@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
      @anon_y_mousse 11 місяців тому

      @@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
      @xhivo97 11 місяців тому

      @@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
    @cusematt23 11 місяців тому +8

    I’ve watched like 50 of your videos this week. Great stuff.

  •  11 місяців тому +7

    Would be interesting what the compiler does.
    If I write x & (0x1 n) & 0x1 with the example above.

    • @metroid031993
      @metroid031993 11 місяців тому +1

      it depends on the compiler, really. I've seen both happen, in different scenarios with the same compiler even.

    • @edgarbonet1
      @edgarbonet1 11 місяців тому +1

      Any half-decent compiler knows how to do constant folding. Thus, if n is a compile-time constant, 0x1

  • @hampus23
    @hampus23 11 місяців тому +6

    Keep up the excellent work with your educational content! 🙌

  • @osamaadil231
    @osamaadil231 11 місяців тому +5

    Very informative! Keep up the good work ❤

  • @deepakr8261
    @deepakr8261 11 місяців тому +2

    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
      @edgarbonet1 11 місяців тому

      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
      @deepakr8261 11 місяців тому

      @@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
      @edgarbonet1 11 місяців тому

      @@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.

  • @GAMarine137
    @GAMarine137 Місяць тому

    Thanks for the video

  • @Psychx_
    @Psychx_ 9 місяців тому +1

    What's the advantage/disadvantage of using defines to create the bitmasks? Can't that also be done using an enum?

  • @godnyx117
    @godnyx117 11 місяців тому

    Top tier content! You are a true OG!

  • @shoyur
    @shoyur 11 місяців тому +1

    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
      @edgarbonet1 11 місяців тому +1

      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.

  • @baguettedad
    @baguettedad 11 місяців тому +7

    But instead of a macro, wouldn't it be easier to use enums for the same purpose?
    Great video btw!

    • @MechPaul
      @MechPaul 11 місяців тому

      Why not both?

    • @baguettedad
      @baguettedad 11 місяців тому +3

      @@MechPaul macros can be a pain to debug

    • @maxaafbackname5562
      @maxaafbackname5562 11 місяців тому +1

      You mean to define the bit constants?

    • @zokalyx
      @zokalyx 11 місяців тому

      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
      @rustycherkas8229 11 місяців тому

      @@zokalyx 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.

  • @bozhidarivaylov5611
    @bozhidarivaylov5611 11 місяців тому

    wow that was a goood one. THANKS!!!!

  • @savantshuia
    @savantshuia 9 місяців тому +1

    What's the typeface you've used for the text on screen?

  • @h_bra
    @h_bra 11 місяців тому

    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
      @pumpkinhead002 11 місяців тому +2

      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
      @Spielix 11 місяців тому

      Creel has a video "Bit Hacks from Beginner to Advanced" with some nice visualizations.

  • @edgeeffect
    @edgeeffect 11 місяців тому +1

    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
      @edgarbonet1 11 місяців тому

      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.

  • @etiennepretorius1993
    @etiennepretorius1993 11 місяців тому +10

    What about a bit field in a struct?

    • @bloom945
      @bloom945 11 місяців тому +5

      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
      @rexjuggler19 11 місяців тому +10

      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
      @hoffiee123 11 місяців тому +3

      @@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
      @gosnooky 11 місяців тому +3

      This is the way

    • @maxaafbackname5562
      @maxaafbackname5562 11 місяців тому +1

      The problem with bitfields is that the order is undefined.
      As in that is undefined if the first bit is bit zero or not

  • @jarlfenrir
    @jarlfenrir 11 місяців тому

    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?

  • @rian0xFFF
    @rian0xFFF 11 місяців тому +1

    Nice

  • @walkero
    @walkero 11 місяців тому

    Great video as always. Thank you

  • @TreeLuvBurdpu
    @TreeLuvBurdpu 11 місяців тому

    Do you recommend that method of looping from the end, rather than starting at the end and then i--?

  • @matiasm.3124
    @matiasm.3124 11 місяців тому

    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
      @marwan7614 11 місяців тому +7

      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
      @matiasm.3124 11 місяців тому +1

      @@marwan7614 very nice explained.. thanks for your time.

  • @blameItleaveit
    @blameItleaveit 11 місяців тому

    It would be great if we could purchase your C course from somewhere instead of juggling from youtube videos

  • @luke-v8c
    @luke-v8c 11 місяців тому

    Could you make a video about nan in c?

  • @bsdooby
    @bsdooby 11 місяців тому

    A bit of bikesheding here: why are you (still) using `void` in an otherwise empty parameter list (here of the main function)?

    • @JacobSorber
      @JacobSorber  11 місяців тому +1

      old habits? 🤔

    • @bsdooby
      @bsdooby 11 місяців тому

      ​@@JacobSorber No offense intended, I was just curious. Thx for your reply!

    • @JacobSorber
      @JacobSorber  11 місяців тому +1

      @@bsdooby none taken. it's a good reminder.

  • @zxuiji
    @zxuiji 11 місяців тому +12

    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
      @casperes0912 11 місяців тому +1

      Find me a machine made after the 486 where the value is different

    • @anon_y_mousse
      @anon_y_mousse 11 місяців тому +1

      @@casperes0912 Does that stop the older machines from existing?

    • @zxuiji
      @zxuiji 11 місяців тому +1

      @@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
      @Hauketal 11 місяців тому +1

      ​@@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
      @casperes0912 11 місяців тому

      I’ll use avx without any runtime checks

  • @artem.pirkhal
    @artem.pirkhal 11 місяців тому

    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
      @DiThi 11 місяців тому

      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
      @artem.pirkhal 11 місяців тому

      @@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
      @DiThi 11 місяців тому

      @@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
      @artem.pirkhal 11 місяців тому

      @@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
      @DiThi 11 місяців тому

      @@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.

  • @jarlfenrir
    @jarlfenrir 11 місяців тому

    When you provided ARCHIVE value, shouldn't it be a 0xA instead of 0x10?

    • @edgarbonet1
      @edgarbonet1 11 місяців тому

      No:
      - 0xA is decimal 10, binary 1010
      - 0x10 is decimal 16, binary 10000.

    • @jarlfenrir
      @jarlfenrir 11 місяців тому

      @@edgarbonet1Right, 0xA would set two flags at once. My bad.

  • @itsdrdy5551
    @itsdrdy5551 11 місяців тому +1

    instead of 0x just use 0b

  • @zacharymiller7573
    @zacharymiller7573 11 місяців тому

    Which editor do you use for programming?

    • @errodememoria
      @errodememoria 11 місяців тому +2

      The one in the video is VSCode

  • @mowinckel10
    @mowinckel10 11 місяців тому

    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
      @pumpkinhead002 11 місяців тому

      C doesn't support binary literals. That is a GCC implementation.

    • @ajtan2607
      @ajtan2607 11 місяців тому

      @@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
      @Spielix 11 місяців тому

      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.

  • @rammrras9683
    @rammrras9683 11 місяців тому +1

    How to toggle a single bit ?

    • @johngangemi1361
      @johngangemi1361 7 місяців тому

      Use the C bitwise NOT operator ~

    • @JacksonBockus
      @JacksonBockus 5 місяців тому +1

      @@johngangemi1361No, use ^ (xor)

  • @lehisluguer9300
    @lehisluguer9300 2 місяці тому

    its a little BIT faster this way

  • @thebirdhasbeencharged
    @thebirdhasbeencharged 11 місяців тому

    Drop the shirt link

  • @hansibull
    @hansibull 11 місяців тому

    I would usually do [sharp]define BITVALUE(X, N) !!((X) & 1

  • @grimvian
    @grimvian 11 місяців тому +1

    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
      @TreeLuvBurdpu 11 місяців тому

      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
      @grimvian 11 місяців тому

      ​@@TreeLuvBurdpu We all have our preferences and I consider myself at a medium level. The best C Teacher I know is Kris Jordan: ua-cam.com/play/PLKUb7MEve0TjHQSKUWChAWyJPCpYMRovO.html

    • @grimvian
      @grimvian 11 місяців тому

      @@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: ua-cam.com/video/443UNeGrFoM/v-deo.html

    • @edgarbonet1
      @edgarbonet1 11 місяців тому

      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
      @grimvian 11 місяців тому

      @@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
    @danielrhouck 11 місяців тому

    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
      @maxaafbackname5562 11 місяців тому +2

      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
      @danielrhouck 11 місяців тому

      @@maxaafbackname5562 Base 256. Pretty much everything operates on a byte at a time and we have byte-addressable RAM not bit-addressable RAM.

    • @HansLemurson
      @HansLemurson 11 місяців тому

      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
      @danielrhouck 11 місяців тому

      @@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
      @HansLemurson 11 місяців тому

      @@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.

  • @TheMeaningofHaste
    @TheMeaningofHaste 11 місяців тому

    Can combine the #defines like this? -> READONLY | HIDDEN

    • @maxaafbackname5562
      @maxaafbackname5562 11 місяців тому +4

      Yes, because there are no overlapping bits in the definitions.

    • @JacobSorber
      @JacobSorber  11 місяців тому +1

      Definitely. Thanks!

    • @rustycherkas8229
      @rustycherkas8229 11 місяців тому +2

      Yes, but you need to take care.
      #define b0 (1u