5

i encountered a bug in some c code i wrote, and while it was relatively easy to fix, i want to be able to understand the issue underlying it better. essentially what happened is i had two unsigned integers (uint32_t, in fact) that, when the modulus operation was applied, yielded the unsigned equivalent of a negative number, a number that had been wrapped and was thus "big". here is an example program to demonstrate:

#include <stdio.h>
#include <stdint.h>

int main(int argc, char* argv[]) {

  uint32_t foo = -1;
  uint32_t u   = 2048;
  uint64_t ul  = 2048;

  fprintf(stderr, "%d\n", foo);
  fprintf(stderr, "%u\n", foo);
  fprintf(stderr, "%lu\n", ((foo * 2600000000) % u));
  fprintf(stderr, "%ld\n", ((foo * 2600000000) % u));
  fprintf(stderr, "%lu\n", ((foo * 2600000000) % ul));
  fprintf(stderr, "%lu\n", foo % ul);

  return 0;

}

this produces the following output, on my x86_64 machine:

-1
4294967295
18446744073709551104
-512
1536
2047

1536 is the number i was expecting, but (uint32_t)(-512) is the number i was getting, which, as you might imagine, threw things off a bit.

so, i guess my question is this: why does a modulus operation between two unsigned numbers, in this case, produce a number that is greater than the divisor (i.e. a negative number)? is there a reason this behavior is preferred?

1
  • 1
    2600000000 is an int (or maybe a 64-bit int - long or long long), which may have caused the result of the multiplication to become a (signed) long. What platform are you on? Commented Jan 19, 2012 at 20:15

2 Answers 2

3

I think the reason is that the compiler is interpreting the 2600000000 literal as a signed 64-bit number, since it does not fit into a signed 32-bit int. If you replace the number with 2600000000U, you should get the result you expect.

Sign up to request clarification or add additional context in comments.

1 Comment

Actually OP invoked UB by passing the wrong format strings to printf.
2

I don't have a reference handy, but I'm pretty sure when you do that multiplication, it promotes them to int64_t, because it needs to coerce the two multiplicands to a signed integral type. Try 2600000000u instead of 2600000000....

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.