Беззнаковое переполнение с оператором modulus в C

Я столкнулся с ошибкой в написанном мною коде на языке Си, и хотя ее было относительно легко исправить, я хочу лучше понять проблему, лежащую в ее основе. По сути, дело в том, что у меня было два беззнаковых целых числа (uint32_t, на самом деле), которые при применении операции модуляции давали беззнаковый эквивалент отрицательного числа, числа, которое было обернуто и поэтому было "большим". Вот пример программы для демонстрации:

#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;

}

на моей машине x86_64 это дает следующий результат:

-1
4294967295
18446744073709551104
-512
1536
2047

1536 - это число, которое я ожидал, но (uint32_t)(-512) - это число, которое я получил, что, как вы можете себе представить, немного сбило ситуацию.

Итак, мой вопрос заключается в следующем: почему операция по модулю между двумя беззнаковыми числами в данном случае дает число, которое больше делителя (т.е. отрицательное число)? Есть ли причина, по которой такое поведение предпочтительно?

5
задан david 19 January 2012 в 20:12
поделиться