所以我有一些代码需要使用 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 版本来拥有这些功能几乎是不可能的。