Hacker News new | ask | show | jobs
by veddox 4000 days ago
It is basically just that :-)

What I don't understand is the following line:

    prndindex = (prndindex+1)&0xff;
(I'm not a C programmer.) AFAIK, the &0xff is a pointer - but what precisely does it do?
6 comments

Sibling posts have correctly pointed out that the & here is a bitwise AND. However, I wanted to note that `&` is also the take-address-of operator in C, which is why you think it has to do with pointers: there are two operators (one taking the address of something, the result of which is a pointer, another taking a bitwise AND); they both use the same symbol "&".

The difference is that the AND is a binary operator — i.e., it takes two arguments:

    A & B
whereas the address-of operator "&" is a "unary" operator; it only takes one argument:

    &A
There can be something before it in a more complete context, such as:

    x = 3 + &y;
(though this is more often conventionally written the other way "&y + 3"; I only use this for demonstration)

But here "+" is the binary operator. (You can't have two binary operators in a row; that would be like "3 + * 2", which is nonsensical.) This is similar to "3 + -2": the negative here is a unary operator, the "+" here is the binary operator "add"

It's not a pointer, it's a bitwise AND.

It's essentially the same[0] as `prndindex = (prndinex+1) % 256`, except bitwise AND takes less effort to compute.

Modulo is essentially[1]: `mod = a - b * (a / b)` unless the compiler can manage to use bitwise shifting/masks instead.

Back when Doom was popular, the bitmask would have been much more efficient.

[0] http://stackoverflow.com/q/3072665/2967113 [1] I'm not 100% positive that's how it's implemented with an IDIV instruction.

Any reasonable compiler will implement x%256 using bitwise arithmetic, but C semantics require that x == d*(x/d) + (x%d), which means that if x is negative (x%256) must be negative, while (x&0xff) will be positive.

This difference means that the AND is still faster than the MOD when used on signed integers, if the compiler is not smart enough to prove that the input will never be negative.

For example, with gcc 4.7.3 the resulting assembly is

  movl %edi, %edx
  sarl $31, %edx
  shrl $24, %edx
  leal (%rdi, %rdx), %eax
  andl $255, %eax
  subl %edx, %eax
I.e., six instructions instead of one. This is still faster than using a divide.
OK, thanks for the clarification everyone!

> there are two operators (one taking the address of something, the result of which is a pointer, another taking a bitwise AND); they both use the same symbol "&".

Don't you just love C? ;-) (On a serious note, I've been meaning to learn it for some time, but didn't yet get down to the nitty-gritty.)

in this case the & is not to point to an adress, but a bitwise and. 0xff is hexadecimal for 255, or 00000000000000000000000011111111 (assuming 32-bit integers), so the logical and masks out the lower 8 bits of (prndindex+1), effectively doing modulo 255.
No, it's a bitwise AND operation. The line adds one to prndindex modulo 256.
Incrementing the index and limiting the value to 0-255 (AND 0xff)?