所以我有一些代码需要使用UUID来存储数据库ID。为了简单起见,我已经使用了v4(随机),并且我没有看到任何真正的理由使用任何其他较少随机版本的UUID。我的UUID类大致定义如下(简化):
class uuid {
public:
static uuid create_v4();
public:
// cut out for simplification...
public:
uint8_t bytes[16];
};
实际生成代码如下所示:
namespace {
uint32_t rand32() {
// we need to do this, because there is no
// gaurantee that RAND_MAX is >= 0xffffffff
// in fact, it is LIKELY to be 0x7fffffff
const uint32_t r1 = rand() & 0x0ff;
const uint32_t r2 = rand() & 0xfff;
const uint32_t r3 = rand() & 0xfff;
return (r3 << 20) | (r2 << 8) | r1;
}
}
uuid uuid::create_v4() {
static const uint16_t c[] = {
0x8000,
0x9000,
0xa000,
0xb000,
};
uuid uuid;
const uint32_t rand_1 = (rand32() & 0xffffffff);
const uint32_t rand_2 = (rand32() & 0xffff0fff) | 0x4000;
const uint32_t rand_3 = (rand32() & 0xffff0fff) | c[rand() & 0x03];
const uint32_t rand_4 = (rand32() & 0xffffffff);
uuid.bytes[0x00] = (rand_1 >> 24) & 0xff;
uuid.bytes[0x01] = (rand_1 >> 16) & 0xff;
uuid.bytes[0x02] = (rand_1 >> 8 ) & 0xff;
uuid.bytes[0x03] = (rand_1 ) & 0xff;
uuid.bytes[0x04] = (rand_2 >> 24) & 0xff;
uuid.bytes[0x05] = (rand_2 >> 16) & 0xff;
uuid.bytes[0x06] = (rand_2 >> 8 ) & 0xff;
uuid.bytes[0x07] = (rand_2 ) & 0xff;
uuid.bytes[0x08] = (rand_3 >> 24) & 0xff;
uuid.bytes[0x09] = (rand_3 >> 16) & 0xff;
uuid.bytes[0x0a] = (rand_3 >> 8 ) & 0xff;
uuid.bytes[0x0b] = (rand_3 ) & 0xff;
uuid.bytes[0x0c] = (rand_4 >> 24) & 0xff;
uuid.bytes[0x0d] = (rand_4 >> 16) & 0xff;
uuid.bytes[0x0e] = (rand_4 >> 8 ) & 0xff;
uuid.bytes[0x0f] = (rand_4 ) & 0xff;
return uuid;
}
这个看起来对我来说是正确的,但我最近收到了来自数据库的错误,说我尝试插入的UUID是重复的。由于这应该是非常不可能的,我不得不假设我的代码可能存在问题。所以任何人都看错了什么?是我的随机UUID生成,不够随意吗?
注意:我不能使用boost的随机数生成或它的UUID库。我希望我可以,但是我与安装了特定版本库的特定系统绑定并获得足够新版本的boost以使这些功能几乎不可能。
答案 0 :(得分:3)
代码对我来说似乎是合理的。正如评论中所提到的,关于rand()是否是这项任务的一个很好的选择存在一些问题,但是你使用它似乎是一种产生32位数据的合理方法,假设有一个更新版本的库正在用于确保低位与高位一样随机(在您的评论中也提到)。
因此,只要rand()函数即使是一个中等程度的好工作,你似乎也不太可能得到重复。所以我的猜测是有一种不同的失败。想到的一些可能性:
只是疯狂的猜测。其中,第三个是我最喜欢的,但如果我正在审查自己的代码,第四个将是我首先怀疑的那个。