Почему __random_r из glibc присваивает переменные, которые он немедленно перезаписывает? - PullRequest
0 голосов
/ 11 ноября 2018

Я искал источник для функции glibc rand (), которая ответ здесь ссылается на .

Перейдя по ссылке, я озадачен кодом для __ random_r () ветви TYPE_0 :

int32_t val = state[0];
val = ((state[0] * 1103515245) + 12345) & 0x7fffffff;
state[0] = val;
*result = val;

Какой смысл переменной val, получить ее, а затем сразу же перезаписать? Структура random_data, которая содержит состояние, ничего необычного .

Как и следовало ожидать, компиляция с -O2 на godbolt дает тот же код, если вы просто исключите val. Есть ли известная причина для этого паттерна?


ОБНОВЛЕНИЕ: Кажется, это была аберрация в версии, на которую ссылается этот ответ, Я обновил там ссылки на версию 2.28 . Возможно, это было что-то, что было временно сделано для облегчения отладки, чтобы содержимое state[0] было легче увидеть в локальном списке наблюдения?

1 Ответ

0 голосов
/ 11 ноября 2018

Ух ты, это действительно какой-то невероятный мусорный код.

Нет оправдания этому.

И не только инициализация val не нужна, факт заключается в том, что state[0] является int32_t, а умножение на 1103515245 будет запускать неопределенное поведение в GCC (целочисленное переполнение) на любой платформе с 32-битной int s (= в основном каждая). А GCC - это компилятор, наиболее часто используемый для компиляции Glibc.


Как отмечает HostileFork , код более поздней версии 2.28 гласит:

int32_t val = ((state[0] * 1103515245U) + 12345U) & 0x7fffffff;
state[0] = val;
*result = val;

При этом не только удаляется бесполезная инициализация, но суффикс U позволяет умножению происходить с целыми числами без знака, избегая неопределенного поведения. & 0x7fffffff гарантирует, что полученное значение вписывается в int32_t и является положительным.

...