0

How can I optimize the following code?

   ( (kbd_flags & KBD_FLAG_SHIFT) && !(kbd_flags & KBD_FLAG_CAPS))
|| (!(kbd_flags & KBD_FLAG_SHIFT) &&  (kbd_flags & KBD_FLAG_CAPS))

Basically, I want to check if either KBD_FLAG_SHIFT or KBD_FLAG_CAPS is set, but not both.

watain
  • 4,838
  • 4
  • 34
  • 35

3 Answers3

1

I would like to share my solution after doing some research. Zodoh's expression can be simplified to

kbd_flags & KBD_FLAG_SHIFT
    ? !(kbd_flags & KBD_FLAG_CAPS)
    :   kbd_flags & KBD_FLAG_CAPS

(Omitting unneeded parentheses and the true and false expressions)

Another interesting way I figured out is the following:

x = kbd_flags & (KBD_FLAG_SHIFT | KBD_FLAG_CAPS);
return x && (x & x - 1) == 0;

This works because of the way two's complement notation is designed. As an example, if kbd_flags is set to 001000, x - 1 will be 000111 and 001000 & 000111 is 000000. As a result, 000000 is equal to 0, thus returning true. The first x expression makes sure that the "no bit set" case is excluded.

It will also work with more than only two bit flags:

#define A 0x01
#define B 0x02
#define C 0x04
#define D 0x08
#define E 0x10
#define F 0x20

x = flags & (A | B | C | D | E | F);
return x && (x & x - 1) == 0;

Here, the expression x && (x & x - 1) == 0 will be true if and only if one of the flags A through F is set.

A quick test (f being the integer holding the flags to test for):

int f, x;
for (f = 0; f <= F + 1; f++) {
    x = f & (A | B | C | D | E | F);
    printf("0x%02x %d%d%d%d%d%d -> %d\n", f
        , (f & A) == A, (f & B) == B, (f & C) == C
        , (f & D) == D, (f & E) == E, (f & F) == F
        , x && (x & x - 1) == 0);
}

This code will output the follwing:

0x00 000000 -> 0
0x01 100000 -> 1
0x02 010000 -> 1
0x03 110000 -> 0
0x04 001000 -> 1
0x05 101000 -> 0
0x06 011000 -> 0
0x07 111000 -> 0
0x08 000100 -> 1
0x09 100100 -> 0
0x0a 010100 -> 0
0x0b 110100 -> 0
0x0c 001100 -> 0
0x0d 101100 -> 0
0x0e 011100 -> 0
0x0f 111100 -> 0
0x10 000010 -> 1
0x11 100010 -> 0
0x12 010010 -> 0
0x13 110010 -> 0
0x14 001010 -> 0
0x15 101010 -> 0
0x16 011010 -> 0
0x17 111010 -> 0
0x18 000110 -> 0
0x19 100110 -> 0
0x1a 010110 -> 0
0x1b 110110 -> 0
0x1c 001110 -> 0
0x1d 101110 -> 0
0x1e 011110 -> 0
0x1f 111110 -> 0
0x20 000001 -> 1
0x21 100001 -> 0

As you can see, x && (x & x - 1) == 0 is true iff one bit is set.

watain
  • 4,838
  • 4
  • 34
  • 35
0

You can use this

(kbd_flags & KBD_FLAG_SHIFT) ? ((kbd_flags & KBD_FLAG_CAPS)? false : true) : ((kbd_flags & KBD_FLAG_CAPS)? true : false)

Else is you know how to use the bits you can use the XOR operator ^.

A = 0000 0001
B = 0000 0000
A ^ B = 0000 0001

A = 0000 0000
B = 0000 0001
A ^ B = 0000 0001

A = 0000 0000
B = 0000 0000
A ^ B = 0000 0000

A = 0000 0001
B = 0000 0001
A ^ B = 0000 0000
Zodoh
  • 100
  • 7
  • I'm not sure what you mean regarding "you can use the XOR operator". Can you explain? – watain Feb 12 '14 at 10:13
  • the XOR operator is the '^' symbol in C. You can use it to compare bit as it's explain right after (with A and B). Like this you can check if you got the right number. Are your macros boolean or integers ? – Zodoh Feb 12 '14 at 13:00
  • I'm aware of the XOR operator in C, I just don't understand how I can use XOR to solve my problem. The macros are bit flags (unsigned integers), `KBD_FLAG_SHIFT` is 0x01 (01b) and 0x02 (10b). – watain Feb 12 '14 at 15:04
  • and what is the type of kbd_flags ? You do a & so you will obtain a value for (kbd_flags & KBD_FLAG_SHIFT) and (kbd_flags & KBD_FLAG_CAPS) if you do !(condition) that's mean that condition have to be zero (or false, but false = 0). So you will have something like : ((1) && !(0)) || (!(0) && (1)) now if you use ^ you will have those 4 cases : 1^0 0^1 0^0 1^1 only 1^0 and 0^1 will return 1 (=true) and pass. with your code it could be something like this : (kbd_flags & KBD_FLAG_SHIFT) ^ (kbd_flags & KBD_FLAG_CAPS) – Zodoh Feb 12 '14 at 15:16
0

To answer more clearly.

(kbd_flags & KBD_FLAG_SHIFT) ^ (kbd_flags & KBD_FLAG_CAPS)

This should work.

Zodoh
  • 100
  • 7
  • In my opinion, this does not work. Due to readability, lets replace `kbd_flags`, `KBD_FLAG_SHIFT` and `KBD_FLAG_CAPS` with `f`, `A` and `B`, respectively. If `f` is `11b` (`A` is `01b` and `B` is `10b`), then `(f & A)` will be `01b` and `(f & B)` will be `10b`. As a result, `(f & A) ^ (f & B)` will be `11b`, which is evaluated as `true`. But it should be `false`, because both flags are set. – watain Feb 13 '14 at 08:45
  • So if you find the possible results you can maybe add != 11b or something like this ? at this point it's begin to not answer your question... Well it would have work with booleans or 0 1 values. – Zodoh Feb 13 '14 at 09:39
  • Yes it would work with boolean values, but the question was related to bit flags. The expression "is bit flag A or B set, but not both" cannot be solved like that in my opinion. – watain Feb 13 '14 at 09:55
  • You are totally right. Sorry for my misunderstanding of the problem. – Zodoh Feb 13 '14 at 10:03