Toggle a given range of unsigned int bits in C

I am trying to replace the following piece of code

// code version 1
unsigned int time_stx = 11; // given range start
unsigned int time_enx = 19; // given range end
unsigned int time     = 0;  // desired output

while(time_stx < time_enx) time |= (1 << time_stx++);

      

with next without loop

// code version 2
unsigned int time_stx = 11;
unsigned int time_enx = 19;
unsigned int time     = (1 << time_enx) - (1 << time_stx);

      

It turns out that in version 1 code, time = 522240;

in version 2 code time = 0;

, when I use

printf("%u\n", time);

      

to compare the result. I would like to know why this is happening and if there is a faster way to switch bits in a given range. My compiler is gcc (Debian 4.9.2-10) 4.9.2.

Edit:

Thank you for your responses. I made a stupid mistake and I feel uncomfortable posting my question without checking my codes. I did

unsigned int time_stx = 11;
unsigned int time_enx = 19;

unsigned int time1    = 0;
while(time_stx < time_enx) time1 |= (1 << time_stx++); // version 1

//// what I should, but forgotten to do
// time_stx = 11;
// time_enx = 19;

// where time_stx = time_enx now...
unsigned int time2    = (1 << time_enx) - (1 << time_stx); // version 2

// then obviously
printf("time1 = %u\n", time1); // time1 = 522240
printf("time2 = %u\n", time2); // time2 = 0

      

I'm sorry about any inconvenience.

Note: Both time_stx

and time_enx

are generated at run time and are not fixed.

As I said, I made a mistake and the problem is resolved now. Thank!

+3


source to share


1 answer


Read Beat Violin Hacks . Even if there is no answer, you will be better educated on beat scripting. Also, the source code just sets the bits in the range; toggling means converting 1 bit to 0 bit and vice versa (usually achieved with ^

or xor).

As for the code, I converted the three expressions to the following C code:

#include <stdio.h>

static void print(unsigned int v)
{
    printf("0x%.8X = %u\n", v, v);
}

static void bit_setter1(void)
{
    unsigned int time_stx = 11; // given range start
    unsigned int time_enx = 19; // given range end
    unsigned int time     = 0;  // desired output

    while (time_stx < time_enx)
        time |= (1 << time_stx++);

    print(time);
}

static void bit_setter2(void)
{
    unsigned int time_stx = 11;
    unsigned int time_enx = 19;
    unsigned int time     = (1 << time_enx) - (1 << time_stx);
    print(time);
}

static void bit_setter3(void)
{
    unsigned int time = 0xFF << 11;
    print(time);
}

int main(void)
{
    bit_setter1();
    bit_setter2();
    bit_setter3();
    return 0;
}

      

When I look at the assembler (GCC 5.1.0 on Mac OS X 10.10.3) I get:

        .globl _main
_main:
LFB5:
LM1:
LVL0:
        subq    $8, %rsp
LCFI0:
LBB28:
LBB29:
LBB30:
LBB31:
LM2:
        movl    $522240, %edx
        movl    $522240, %esi
        leaq    LC0(%rip), %rdi
        xorl    %eax, %eax
        call    _printf
LVL1:
LBE31:
LBE30:
LBE29:
LBE28:
LBB32:
LBB33:
LBB34:
LBB35:
        movl    $522240, %edx
        movl    $522240, %esi
        xorl    %eax, %eax
        leaq    LC0(%rip), %rdi
        call    _printf
LVL2:
LBE35:
LBE34:
LBE33:
LBE32:
LBB36:
LBB37:
LBB38:
LBB39:
        movl    $522240, %edx
        movl    $522240, %esi
        xorl    %eax, %eax
        leaq    LC0(%rip), %rdi
        call    _printf
LVL3:
LBE39:
LBE38:
LBE37:
LBE36:
LM3:
        xorl    %eax, %eax
        addq    $8, %rsp
LCFI1:
        ret

      

This is an amazingly large collection of shortcuts!



The compiler has fully evaluated all three minimal functions bit_setterN()

and injected them along with the call print

into the body main()

. This includes evaluating expressions up to 522240 each time.

Compilers are good at optimization. Write clean code and let them on top of it and they will be better optimized than you can. Clearly, if 11 and 19 are not fixed in your code (they are sort of computed variables that can change at runtime), then pre-compilation is not that easy (and bit_setter3()

is not a starter). Then the code without the loop will work just like the code for the loop.

To write the output:

0x0007F800 = 522240
0x0007F800 = 522240
0x0007F800 = 522240

      

If your Debian compiler gives you zero from one of the code snippets, then there is either a difference between what you compiled and what you posted, or a bug in the compiler. All in all, and there was no disrespect, it is more likely that you made a mistake than that the compiler has a bug that pops up in your code as easily as this.

+2


source







All Articles