所以我有一些代码需要使用 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 库。我希望我可以,但是我被绑定(bind)到安装了特定版本库的特定系统,并且获得足够新的 boost 版本来拥有这些功能几乎是不可能的。

最佳答案

代码对我来说似乎是合理的。正如评论中所提到的,关于 rand() 是否是执行此任务的好选择存在一些问题,但是假设正在使用较新版本的库,您对它的使用似乎是生成 32 位数据的合理方法用于确保低位与高位一样随机(也在您的评论中提到)。

因此,只要 rand() 函数的性能还算不错,您就不太可能得到重复项。所以我的猜测是有一种不同的失败。想到的一些可能性:

  • 时间(0)失败。这似乎不太可能。如果它返回 -1 以指示在两次不同的运行中出现错误,则可能会导致问题。但是,它应该能够失败的唯一方法是给它一个无效的地址(这里绝对不是这种情况)。
  • 多线程使用。我不认为 rand() 是线程安全的。如果在多线程情况下使用此代码,可能会导致意外行为。
  • Cron 造成困难。如果工作站上的时钟不准确并且它被自动设置(例如,通过 rdate)与某些服务器同步,那么它可能会导致在某个时间重复 cron 作业。我能够简单地通过创建一个 cron 作业来模拟这种行为,每分钟将当前日期转储到一个文件,然后重复设置日期......它最终将相同的日期/时间(到秒)写入文件更多不止一次。使用时间函数的一秒分辨率,这很容易导致重复种子。
  • 将 UUID 写入数据库的代码不正确。即使 UUID 生成器运行良好,也可能存在不同的错误,将相同的 UUID 两次写入数据库。

  • 只是胡乱猜测。其中,第三个是我最喜欢的,但如果我正在审查自己的代码,第 4 个将是我首先怀疑的。

    关于c++ - 这个 UUID 生成代码有问题吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12322985/

    10-16 04:49