如何在C语言中生成GUID?

5
我希望生成GUID以插入SQLite数据库(即没有来自数据库的支持)。但是,我想控制某些属性:
  1. 有序性,以生成递增的GUID值。
  2. 计算机独立性。数据库是公共的,可能/可能不想让GUID允许某人追溯数据到特定的机器。
  3. 足够随机性。 GUID是数据库中的键,将与许多其他数据库合并,并且可能变得非常大,这意味着像许多算法一样伪造GUID是不好的。
  4. 我可以使用系统特定的API处理,但请链接Windows和Linux函数,最好使用像SQLite这样的东西,我可以只使用别人编写的代码。
  5. 我也希望使用商业应用程序中可接受的代码。

4个回答

7

在创建包含作者所需元素的GUID答案方面,PHP是一个重要的参考来源。您可以访问http://us3.php.net/uniqid以查看相关示例。在示例中,他们介绍了如何添加服务器名称,数据库名称和其他元素到GUID。

然而,为了满足C语言的GUID函数需求,以下代码基于JavaScript函数编写。您可以参考Create GUID / UUID in JavaScript?。此示例使用了正则表达式来创建GUID。

下面是一个基于JavaScript示例的创建GUID代码。我相信还有更优雅的解决方案。这只是一些拼凑而成的东西,旨在帮助提供一个干净的示例供其他人参考。

srand (clock());
char GUID[40];
int t = 0;
char *szTemp = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx";
char *szHex = "0123456789ABCDEF-";
int nLen = strlen (szTemp);

for (t=0; t<nLen+1; t++)
{
    int r = rand () % 16;
    char c = ' ';   

    switch (szTemp[t])
    {
        case 'x' : { c = szHex [r]; } break;
        case 'y' : { c = szHex [r & 0x03 | 0x08]; } break;
        case '-' : { c = '-'; } break;
        case '4' : { c = '4'; } break;
    }

    GUID[t] = ( t < nLen ) ? c : 0x00;
}

printf ("%s\r\n", GUID);

注意:字符串以0x00字符结尾。

1
这不是GUID,只是一个格式化的随机数。 - Luciano
这是一个版本为4的随机UUID,完全有效。 - Lawrence Dol
1
除了极度弱的随机种子外,一切都有效。 - Lawrence Dol
可以通过用default: break;替换最后两个情况,初始化c = szTemp[t]并替换switch (c)来稍微改进一下。 - Qix - MONICA WAS MISTREATED

4
首先,GUID并非随机生成的,它们具有非常明确定义的数学规则。
至于你的问题,将GUID创建作为存储过程放入数据库中,这样系统就可以跨平台使用。然后,将GUID作为自增整数,并在前面添加一个数据库ID作为前缀。这个前缀使得不同数据库之间可以轻松合并。数据库ID需要对每个数据库都唯一。如果你控制每个数据库,则容易确保它们是唯一的。否则,你可能需要一个查找系统,将数据库IP地址(或其他唯一标识符)映射到唯一的数据库ID。
如果没有存储过程,则创建一个带有“NextIndex”和“DatabaseID”字段的表,并在添加新记录时更新它们:
read NextIndex and DatabaseID
increment NextIndex
ID = NextIndex + DatabaseID
add new record, setting "GUID" to the ID value

问题在于数据库是在不同的位置创建的,没有中央机构,因此没有管理人员可以验证唯一性。 - chacham15
@chacham:数据库ID可以是MAC地址、操作系统生成的GUID等。 - Skizz

4
你可以使用或查看Boost.Uuid的代码:

http://www.boost.org/doc/libs/1_47_0/libs/uuid/index.html

这是一个C++库,但你仍然可以在其中找到作者如何在多个系统上检索Uuid的方法。截至我上次检查(2010年1月),我至少发现了以下Windows和Linux / Solaris实现(此信息可能已过时):

Linux/Solaris上的UUID/GUID

打开一个文件/dev/urandom并读取足够的字节(16个)以组成GUID / UUID。

Windows上的UUID / GUID

使用以下WinAPI函数:

其他实现

GUID / UUID的维基百科页面列出了您可以使用/研究的替代实现:

https://en.wikipedia.org/wiki/UUID#Implementations

关于你的条件

有一种GUID/UUID类型始终是随机的(版本4),这意味着为了与其他GUID/UUID语义兼容,您应该尊重它。

现在,您希望GUID/UUID按时间排序。唯一不削弱GUID/UUID随机性的方法是在16字节的GUID/UUID前加上一个无符号整数(这将使您的标识符数据为20字节或更多,具体取决于您的整数)。只需生成一个GUID/UUID,并增加整数即可。


libuuid在Linux上足够小,不需要使用Boost的UUID机制。 - jørgensen
1
@jørgensen:libuuid在Linux上足够小,不需要使用Boost的UUID机制:这不是我的回答吗?查看Boost以了解/提取在每个平台上如何完成的方法?... - paercebal

0

这是一个Linux示例。Linux有一个用于生成uuid的头文件uuid.h。对于我的Ubuntu 20.x操作系统,uuid.h头文件位于/usr/include/uuid/。

/* uuid.c
 * 
 * Defines function uuid
 *
 * Print a universally unique identifer, created using Linux uuid_generate.
 *
 * 
 * Compile
 *
 * gcc uuid.c -o uuid -luuid -Wall -g
 *
 *
 * Run
 * 
 * ./uuid
 * 
 *
 * Debug
 *
 * gdb uuid
 * b main
 * r
 *
 */

#include <stdlib.h>
#include <stdio.h>
#include <uuid/uuid.h>

char* uuid(char out[UUID_STR_LEN]){
  uuid_t b;
  uuid_generate(b);
  uuid_unparse_lower(b, out);
  return out;
}

int main(){
  char out[UUID_STR_LEN]={0};
  puts(uuid(out));
  return EXIT_SUCCESS;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接