1

the purpose of my code is to create a mask of n zeroes to the right of my int (32 bits) representation. My approach was first to have the negative one stored in a variable and then shift it left n spaces to have n zeroes to the right. The code is the following:

int mask(int n){
  int neg1=(1<<31)>>31;
  int mask=neg1<<n;
  return mask;
}

Nonetheless when n is 32 I would like to get the value 0x0, but instead I am getting 0xffffffff (neg1). That happens when I do the shift to the variable. But when I do the shift to the constant itself, it works like a charm. The new code would be:

mask=0xffffffff<<n;

Nonetheless, I'm not allowed to use constants of more than 8 bits. So I need the value stored in another variable. Can somebody tell me why is this happening and how can I solve it?

Thank you so much!

Aldo Pareja
  • 469
  • 2
  • 10
  • 2
    The shift you're trying to do is undefined behavior. Also, why are you doing `(1<<31)>>31` (also undefined behavior) to get `-1`? – user2357112 May 25 '16 at 22:14
  • Note: Shifting left into the sign bit is UB. and "An example of implementation-defined behavior is the propagation of the high-order bit when a signed integer is shifted right." so `int neg1=(1<<31)>>31;` may not execute as expected. – chux - Reinstate Monica May 25 '16 at 22:14
  • 3
    Must code use `int`? How about `unsigned`? Lots less issues. – chux - Reinstate Monica May 25 '16 at 22:16
  • 2
    You should be able to add an `if(n >= 32) mask = 0; else ...` statement to deal with that case. – Hill May 25 '16 at 22:17
  • 1
    So `mask(0) --> 0xFFFFFFFF`, `mask(1) --> 0xFFFFFFFE` ... `mask(31) --> 0x80000000` and `mask(32) --> 0`? Does code need to handle other values of `n`? – chux - Reinstate Monica May 25 '16 at 22:20
  • My question is not answered in the question proposed by M.M. I understand why I am getting -1 as the result of 1<<31>>31. What I don't understand is what I asked. – Aldo Pareja May 26 '16 at 00:28

1 Answers1

1

OP's code invokes undefined behavior when trying to shift left into the sign bit of a 32-bit int.

The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with zeros. ... If E1 has a signed type and nonnegative value, and E1 × 2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined. C11 §6.5.7 4

Instead use unsigned types to avoid ill-defined behavior with a shift of 31. A shift of 32+ on a 32-bit unsigned will be a problem too.

A simple approach uses a wider type.

#include <stdio.h>
#include <inttypes.h>

uint32_t mask32(int n) {
  return 0 - (1ull << n);
}

int main(void) {
  for (int i=0; i<=32; i++) {
    printf("%2d %lX\n", i, (unsigned long) mask32(i));
  }
}

Output

 0 FFFFFFFF
 1 FFFFFFFE
 2 FFFFFFFC
 ...
29 E0000000
30 C0000000
31 80000000
32 0
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • Thank you so much!... I just didn't know it was an undefined behavior. Although it was pretty weird that when doing it with a constant I was getting what I wanted and when doing it with a variable I was getting the other thing!. – Aldo Pareja May 26 '16 at 00:26
  • 1
    @Aldo Pareja unclear by the statement "doing it with a constant I was getting what I wanted and when doing it with a variable". Detail `1<<31` with 32-bit `int` is UB because 1 (an `int`) is shifted into the sign bit. `0xffffffff` is an `unsigned` and shifting a 32-bit `unsigned` by 0 to 31 is well defined. – chux - Reinstate Monica May 26 '16 at 01:22