Я просмотрел стандарт C (с 1999 года), и он говорит только, что RAND_MAX
должен быть не менее 32767, но ничего не говорит о том, должен ли этот макрос расширяться до подписанного или беззнакового int. Спецификация Single UNIX (ссылка 1, ссылка 2) и Linux man (ссылка) не добавляют ясности.
Казалось бы, RAND_MAX
должен быть signed int
, так как возвращается rand()
.
Однако я обнаружил, что некоторые компиляторы определяют его как unsigned:
- Древний Turbo С++ 1.01: #define RAND_MAX 0x7FFFU
- Не так древний С++ Builder 5.5: #define RAND_MAX 0x7FFFU
- Все еще жив Open Watcom C/С++ 1.9: #define RAND_MAX 32767U
- DJGPP (gcc 3.3.4 для DOS): #define RAND_MAX 2147483647
- MinGW (gcc 4.6.2 для Windows): #define RAND_MAX 0x7FFF
- MS Visual Studio 2010 (ссылка): RAND_MAX определяется как значение 0x7fff
- Tiny C Compiler 0.9.25: #define RAND_MAX 0x7FFF
- lcc-win32 3.8: #define RAND_MAX 0x7fff
- Pelles C 6.50: #define RAND_MAX 0x3fffffff ИЛИ #define RAND_MAX 0x7fff
- Digital Mars C/С++ 8.52: #define RAND_MAX 32767
Это делает, казалось бы, безобидный код, похожий на ниже, стать не переносимым и взорваться из-за подписания без подписи:
cos(w * t) + (rand() - RAND_MAX / 2) * 0.1 / (RAND_MAX / 2);
rand()
возвращает a signed int
в диапазоне [0, RAND_MAX
].
Если RAND_MAX
определяется как unsigned int
, значение из rand()
также увеличивается до unsigned int
.
И если в этом случае разность (rand() - RAND_MAX / 2)
становится беззнаковым разностью беззнаковых целых чисел со значением в диапазонах [0, RAND_MAX
- RAND_MAX
/2] и [UINT_MAX
+ 1- RAND_MAX
/2, UINT_MAX
-1] вместо того, чтобы быть знаковой разностью знаковых целых чисел со значением в диапазоне [- RAND_MAX
/2, RAND_MAX
- RAND_MAX
/2].
Во всяком случае, похоже, что RAND_MAX
должен быть подписан, и большинство (?) компиляторов определяют его как таковое, но есть ли какой-либо авторитетный источник, который говорит, что он должен быть подписан? Старые стандарты? К & усилителя, R? Еще одна спецификация UNIX?