我一直在寻找glibc的rand()函数的来源,an answer here links to。
在链接之后,我对__random_r() TYPE_0 branch的代码感到困惑:
int32_t val = state[0];
val = ((state[0] * 1103515245) + 12345) & 0x7fffffff;
state[0] = val;
*result = val;
val
变量被赋值然后立即被覆盖的意义是什么?保持状态的random_data
结构是nothing unusual。
正如人们所期望的那样,如果只删除-O2
,则在godbolt上使用val
进行编译会得到相同的代码。有这种模式的已知原因吗?
更新:这似乎是该答案I've updated the links there to the 2.28 version所链接的版本中的一个异常。通过使state[0]
的内容更易于在本地监视列表中查看,可能是暂时进行的调试操作。
答案 0 :(得分:1)
哇,那确实是一些令人难以置信的垃圾代码。
没有任何理由。
不仅不需要初始化val
,而且事实是state[0]
是int32_t
,并且与1103515245
相乘将在具有32位int
(基本上是每个)的任何平台上,在GCC中触发不确定的行为(整数溢出)。 GCC是最常用于编译Glibc的编译器。
如HostileFork所述,最新的2.28版本中的代码为:
int32_t val = ((state[0] * 1103515245U) + 12345U) & 0x7fffffff;
state[0] = val;
*result = val;
这样,不仅删除了无用的初始化,而且后缀U
使无符号整数发生乘法运算,从而避免了不确定的行为。 & 0x7fffffff
确保结果值适合int32_t
并且为正。