一个UUID生成算法的C语言实现 --- WIN32版本 .

简介: 一个UUID生成算法的C语言实现——WIN32版本   cheungmine 2007-9-16   根据定义,UUID(Universally Unique IDentifier,也称GUID)在时间和空间都是唯一的。
一个UUID生成算法的C语言实现——WIN32版本
 
cheungmine
2007-9-16
 
根据定义,UUID(Universally Unique IDentifier,也称GUID)在时间和空间都是唯一的。为保证空间的唯一性,每个UUID使用了一个48位的值来记录,一般是计算机的网卡地址。为保证时间上的唯一性,每个UUID具有一个60位的时间戳(timestamp)。这个时间戳表示自公元1582年(绝对不是1852,这是《COM技术内幕》,1999年3月第1版第89页中的一个错误)10月15号00:00:00:00以来的时间,是以100纳秒为单位的时间间隔。1纳秒(ns)=10 -9秒(s)。UUID算法可以保证至大约公元3400年仍然唯一。UUID的C语言结构定义如下:
 
typedef struct _uuid_t
{
     unsigned long      data1;       
     unsigned short     data2;
     unsigned short     data3;
     unsigned char      data4[8];
} uuid_t;
 
它的结构大小为16个字节。即sizeof(uuid_t)==16为TRUE。写成16进制字符串的格式,一般为:
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
 
上面的字符串形式,占用36个字符,不包括结尾空字符’/0’。所以,要想容纳一个UUID字符串,必须声明为一个char[36+1]的字符数组。
 
以软件算法实现UUID非常有现实意义。参考RFC4122文档和其他一些开源代码,我写了一个WIN32下的UUID实现C语言程序——UUID32.c。程序符合RFC4122标准。程序不但实现创建UUID和UUID String,还可以对UUID进行字符和时间上的比较。还可以从UUID从提取时间戳(精度到秒)。头文件uuid32.h定义如下:
/*  uuid32.h 
   2007-09-15 Last created by cheungmine.
   Partly rights reserved by cheungmine.
*/
#ifndef UUID32_H_INCLUDED
#define  UUID32_H_INCLUDED

#include 
< stdlib.h >
#include 
< assert.h >
#include 
< string .h >
#include 
< memory.h >

#include 
" cdatatype.h "

typedef 
struct  _timestamp_t
{
    BYTE    tm_sec;                
/*  Seconds after minute (0 – 59).  */
    BYTE    tm_min;                
/*  Minutes after hour (0 – 59).  */
    BYTE    tm_hour;            
/*  Hours after midnight (0 – 23).  */
    BYTE    tm_mday;            
/*  Day of month (1 – 31).  */
    BYTE    tm_mon;                
/*  Month (0 – 11; January = 0).  */
    BYTE    tm_wday;            
/*  Day of week (0 – 6; Sunday = 0).  */
    
short     tm_year;             /*  Year (current year minus 1900).  */
    
short     tm_yday;             /*  Day of year (0 – 365; January 1 = 0).  */
    
long     tm_fraction;         /*  Fraction little than 1 second  */
} timestamp_t;

typedef 
struct  _uuid_t
{
    unsigned 
long     data1;
    unsigned 
short     data2;
    unsigned 
short     data3;
    unsigned 
char     data4[ 8 ];
} uuid_t;


/* *
 * Checks whether the given string matches the UUID format.
 *    params:
 *     [in] uuid - the potential UUID string
 *    return 
 *     TRUE if the given string is a UUID, FALSE otherwise
 *
*/
BOOL is_uuid_string(
const   char   * uuid);

/* *
 * Generates a new UUID. The UUID is a time-based time 1 UUID.
 * A random per-process node identifier is used to avoid keeping global
 * state and maintaining inter-process synchronization.
 *
*/
void  uuid_create(uuid_t *  uuid);

/* *
 * Generates a new UUID string. The returned UUID is a time-based time 1 UUID.
 * A random per-process node identifier is used to avoid keeping global
 * state and maintaining inter-process synchronization.
 *  return UUID string (newly allocated)
 *
*/
char   * uuid_create_string( void );

/* *
 * Generates a name-based (type 3) UUID string from the given external
 * identifier. The special namespace UUID is used as the namespace of
 * the generated UUID.
 *  params
 *     [in] external - the external identifier
 *  return 
 *     UUID string (newly allocated)
 *
*/
void  uuid_create_external( const   char   * external, uuid_t *  uuid);

/* *
 * Translate a uuid_t to a uuid string
 *  return UUID string
 *
*/
char   * uuid_to_string( const  uuid_t *  uuid);

/* *
 * Get timestamp from a UUID
 *
*/
void  uuid_to_timestamp( const  uuid_t *  uuid, timestamp_t *  time);


/* *
 * Resurn a description of timestamp NOT including fraction
 *
*/
char *  timestamp_to_string( const  timestamp_t *  time);

/* *
 * Compare two UUID's lexically
 *    return
 *      -1   u1 is lexically before u2
 *     0   u1 is equal to u2
 *     1   u1 is lexically after u2
*/
int  uuid_compare( const  uuid_t  * u1,  const  uuid_t  * u2);

/* *
 * Compare two UUID's temporally
 *    return
 *      -1   u1 is temporally before u2
 *     0   u1 is equal to u2
 *     1   u1 is temporally after u2
*/
int  uuid_compare_time( const  uuid_t  * u1,  const  uuid_t  * u2);


#endif         /* UUID32_H_INCLUDED */
 
  
       其中,头文件"cdatatype.h"如下:
 
 
/*  cdatatype.h 
   2008-09-15 Last created by cheungmine.
   All rights reserved by cheungmine.
*/
#ifndef CDATATYPE_H__
#define  CDATATYPE_H__

/* ============================================================================ */
typedef unsigned 
char  uchar,  byte , BYTE;

typedef unsigned 
short  uint16, word_t,  ushort ;

typedef unsigned 
int   uint , uint32, dword_t, size_t;

typedef unsigned 
long   ulong ;

typedef __int64 int64;
typedef unsigned __int64 uint64, qword_t;


#ifndef BOOL
    
#define  BOOL  int
    
#define  TRUE  1
    
#define  FALSE 0
#endif

#ifndef RESULT
    
#define  RESULT  long
    
#define  SUCCESS        0
    
#define  ERROR        -1
#endif

#define  SIZE_BYTE    1
#define  SIZE_SHORT    2
#define  SIZE_INT    4
#define  SIZE_FLT    4
#define  SIZE_DBL    8
#define  SIZE_WORD    2
#define  SIZE_DWORD    4
#define  SIZE_QWORD    8
#define  SIZE_LINT    8
#define  SIZE_INT64    8
#define  SIZE_UUID    16

/* ============================================================================ */
#endif     /*CDATATYPE_H__*/

           MD5算法生成的文件有:md5.h和md5.c,分别罗列如下:

 

#ifndef _MD5_H__
#define  _MD5_H__
/*  MD5.H - header file for MD5C.C  */

/*  Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
   rights reserved.

   License to copy and use this software is granted provided that it
   is identified as the "RSA Data Security, Inc. MD5 Message-Digest
   Algorithm" in all material mentioning or referencing this software
   or this function.

   License is also granted to make and use derivative works provided
   that such works are identified as "derived from the RSA Data
   Security, Inc. MD5 Message-Digest Algorithm" in all material
   mentioning or referencing the derived work.

   RSA Data Security, Inc. makes no representations concerning either
   the merchantability of this software or the suitability of this
   software for any particular purpose. It is provided "as is"
   without express or implied warranty of any kind.

   These notices must be retained in any copies of any part of this
   documentation and/or software.

   2007-09-15 Last modified by cheungmine.
 
*/

/*  MD5 context.  */
typedef 
struct  {
    unsigned 
int  state[ 4 ];                 /*  state (ABCD)  */
    unsigned 
int  count[ 2 ];                 /*  number of bits, modulo 2^64 (lsb first)  */
    unsigned 
char  buffer[ 64 ];     /*  input buffer  */
} MD5_CTX;

void   MD5_init (MD5_CTX  * );
void   MD5_update (MD5_CTX  * const  unsigned  char   * str, unsigned  int  len);
void   MD5_fini (unsigned  char [ 16 ], MD5_CTX  * );

char *  MD5_sign ( const  unsigned  char   * str, unsigned  int  len);

#endif     /* _MD5_H__ */

 

/*  
 * md5.c - Copyright 1997 Lachlan Roche 
 *       - Modified by cheungmine, 2007-9-15
 
*/

#include 
< stdio.h >
#include 
< stdlib.h >
#include 
< string .h >
#include 
< memory.h >
#include 
" md5.h "

#define  MD5STR_LEN        32    


/* =====================================================================
   The remaining code is the reference MD5 code (md5c.c) from rfc1321
   MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm

   Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
   rights reserved.

   License to copy and use this software is granted provided that it
   is identified as the "RSA Data Security, Inc. MD5 Message-Digest
   Algorithm" in all material mentioning or referencing this software
   or this function.

   License is also granted to make and use derivative works provided
   that such works are identified as "derived from the RSA Data
   Security, Inc. MD5 Message-Digest Algorithm" in all material
   mentioning or referencing the derived work.

   RSA Data Security, Inc. makes no representations concerning either
   the merchantability of this software or the suitability of this
   software for any particular purpose. It is provided "as is"
   without express or implied warranty of any kind.

   These notices must be retained in any copies of any part of this
   documentation and/or software.
=====================================================================
*/

/*  Constants for _MD5Transform routine.  */
#define  S11 7
#define  S12 12
#define  S13 17
#define  S14 22
#define  S21 5
#define  S22 9
#define  S23 14
#define  S24 20
#define  S31 4
#define  S32 11
#define  S33 16
#define  S34 23
#define  S41 6
#define  S42 10
#define  S43 15
#define  S44 21

static   void  _MD5Transform(unsigned  int [ 4 ],  const  unsigned  char [ 64 ]);
static   void  _Encode(unsigned  char   * , unsigned  int   * , unsigned  int );
static   void  _Decode(unsigned  int   * const  unsigned  char   * , unsigned  int );

static  unsigned  char  PADDING[ 64 =  {
    
0x80 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ,
    
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ,
    
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
};

/*  F, G, H and I are basic MD5 functions.  */
#define  F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define  G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define  H(x, y, z) ((x) ^ (y) ^ (z))
#define  I(x, y, z) ((y) ^ ((x) | (~z)))

/*  ROTATE_LEFT rotates x left n bits.  */
#define  ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))

/*  FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
   Rotation is separate from addition to prevent recomputation. 
*/
#define  FF(a, b, c, d, x, s, ac) { 
 (a) 
+=  F ((b), (c), (d))  +  (x)  +  (unsigned  int )(ac); 
 (a) 
=  ROTATE_LEFT ((a), (s)); 
 (a) 
+=  (b); 
  }
#define  GG(a, b, c, d, x, s, ac) { 
 (a) 
+=  G ((b), (c), (d))  +  (x)  +  (unsigned  int )(ac); 
 (a) 
=  ROTATE_LEFT ((a), (s)); 
 (a) 
+=  (b); 
  }
#define  HH(a, b, c, d, x, s, ac) { 
 (a) 
+=  H ((b), (c), (d))  +  (x)  +  (unsigned  int )(ac); 
 (a) 
=  ROTATE_LEFT ((a), (s)); 
 (a) 
+=  (b); 
  }
#define  II(a, b, c, d, x, s, ac) { 
 (a) 
+=  I ((b), (c), (d))  +  (x)  +  (unsigned  int )(ac); 
 (a) 
=  ROTATE_LEFT ((a), (s)); 
 (a) 
+=  (b); 
  }

/*  MD5 initialization. Begins an MD5 operation, writing a new context.  */
void  MD5_init(MD5_CTX  *  context)
{
    context
-> count[ 0 =  context -> count[ 1 =   0 ;
    
/*  Load magic initialization constants.  */
    context
-> state[ 0 =   0x67452301 ;
    context
-> state[ 1 =   0xefcdab89 ;
    context
-> state[ 2 =   0x98badcfe ;
    context
-> state[ 3 =   0x10325476 ;
}

/*  MD5 block update operation. Continues an MD5 message-digest operation, 
   processing another message block, and updating the context. 
*/
void  MD5_update(MD5_CTX  *  context,  const  unsigned  char   * input, unsigned  int  inputLen)
{
    unsigned 
int  i, index, partLen;

    
/*  Compute number of bytes mod 64  */
    index 
=  (unsigned  int ) ((context -> count[ 0 >>   3 &   0x3F );

    
/*  Update number of bits  */
    
if  ((context -> count[ 0 +=  ((unsigned  int ) inputLen  <<   3 ))  <  ((unsigned  int ) inputLen  <<   3 ))
        context
-> count[ 1 ] ++ ;
    context
-> count[ 1 +=  ((unsigned  int ) inputLen  >>   29 );

    partLen 
=   64   -  index;

    
/*  Transform as many times as possible.  */
    
if  (inputLen  >=  partLen) {
        memcpy((
void   * & context -> buffer[index], ( void   * ) input, partLen);
        _MD5Transform(context
-> state, context -> buffer);

        
for  (i  =  partLen; i  +   63   <  inputLen; i  +=   64 )
            _MD5Transform(context
-> state,  & input[i]);

        index 
=   0 ;
    }
    
else
        i 
=   0 ;

    
/*  Buffer remaining input  */
    memcpy((
void   * & context -> buffer[index], ( void   * & input[i], inputLen  -  i);
}

/*  MD5 finalization. Ends an MD5 message-digest operation, writing the message digest and zeroizing the context.  */
void  MD5_fini(unsigned  char  digest[ 16 ], MD5_CTX  *  context)
{
    unsigned 
char  bits[ 8 ];
    unsigned 
int  index, padLen;

    
/*  Save number of bits  */
    _Encode(bits, context
-> count,  8 );

    
/*  Pad out to 56 mod 64.  */
    index 
=  (unsigned  int ) ((context -> count[ 0 >>   3 &   0x3f );
    padLen 
=  (index  <   56 ?  ( 56   -  index) : ( 120   -  index);
    MD5_update(context, PADDING, padLen);

    
/*  Append length (before padding)  */
    MD5_update(context, bits, 
8 );

    
/*  Store state in digest  */
    _Encode(digest, context
-> state,  16 );

    
/*  Zeroize sensitive information. */
    memset((
void   * ) context,  0 sizeof  ( * context));
}

#pragma  warning(push)    /* C4996 */
#pragma  warning( disable : 4996 )

char *  MD5_sign ( const  unsigned  char   * str, unsigned  int  len)
{
    
int  i;
    MD5_CTX     md5;
    
static   char  md5_str[MD5STR_LEN + 1 ];
    
char  hash[ 16 ], tmp[ 3 ];
    md5_str[
0 =   0 ;
            
    MD5_init(
& md5);
    MD5_update (
& md5, str, len);
    MD5_fini (hash, 
& md5);
        
    
for  ( i  =   0  ; i  <   16  ; i ++  )
    {
        _itoa((unsigned 
char )hash[i], tmp ,  16 );

        
if  (tmp[ 1 ==   0 ){
            tmp[
2 ] = 0 ;    tmp[ 1 ] = tmp[ 0 ]; tmp[ 0 ] = ' 0 ' ;
        }
        strcat(md5_str, tmp);
    }

    
return  md5_str;
}

#pragma  warning(pop)    /* C4996 */

/*  MD5 basic transformation. Transforms state based on block.  */
static   void  _MD5Transform(unsigned  int  state[ 4 ],  const  unsigned  char  block[ 64 ])
{
    unsigned 
int  a  =  state[ 0 ], 
                 b 
=  state[ 1 ], 
                 c 
=  state[ 2 ], 
                 d 
=  state[ 3 ], 
                 x[
16 ];

    _Decode(x, block, 
64 );

    
/*  Round 1  */
    FF(a, b, c, d, x[
0 ], S11,  0xd76aa478 );     /*  1  */
    FF(d, a, b, c, x[
1 ], S12,  0xe8c7b756 );     /*  2  */
    FF(c, d, a, b, x[
2 ], S13,  0x242070db );     /*  3  */
    FF(b, c, d, a, x[
3 ], S14,  0xc1bdceee );     /*  4  */
    FF(a, b, c, d, x[
4 ], S11,  0xf57c0faf );     /*  5  */
    FF(d, a, b, c, x[
5 ], S12,  0x4787c62a );     /*  6  */
    FF(c, d, a, b, x[
6 ], S13,  0xa8304613 );     /*  7  */
    FF(b, c, d, a, x[
7 ], S14,  0xfd469501 );     /*  8  */
    FF(a, b, c, d, x[
8 ], S11,  0x698098d8 );     /*  9  */
    FF(d, a, b, c, x[
9 ], S12,  0x8b44f7af );     /*  10  */
    FF(c, d, a, b, x[
10 ], S13,  0xffff5bb1 );     /*  11  */
    FF(b, c, d, a, x[
11 ], S14,  0x895cd7be );     /*  12  */
    FF(a, b, c, d, x[
12 ], S11,  0x6b901122 );     /*  13  */
    FF(d, a, b, c, x[
13 ], S12,  0xfd987193 );     /*  14  */
    FF(c, d, a, b, x[
14 ], S13,  0xa679438e );     /*  15  */
    FF(b, c, d, a, x[
15 ], S14,  0x49b40821 );     /*  16  */

    
/*  Round 2  */
    GG(a, b, c, d, x[
1 ], S21,  0xf61e2562 );     /*  17  */
    GG(d, a, b, c, x[
6 ], S22,  0xc040b340 );     /*  18  */
    GG(c, d, a, b, x[
11 ], S23,  0x265e5a51 );     /*  19  */
    GG(b, c, d, a, x[
0 ], S24,  0xe9b6c7aa );     /*  20  */
    GG(a, b, c, d, x[
5 ], S21,  0xd62f105d );     /*  21  */
    GG(d, a, b, c, x[
10 ], S22,  0x2441453 );     /*  22  */
    GG(c, d, a, b, x[
15 ], S23,  0xd8a1e681 );     /*  23  */
    GG(b, c, d, a, x[
4 ], S24,  0xe7d3fbc8 );     /*  24  */
    GG(a, b, c, d, x[
9 ], S21,  0x21e1cde6 );     /*  25  */
    GG(d, a, b, c, x[
14 ], S22,  0xc33707d6 );     /*  26  */
    GG(c, d, a, b, x[
3 ], S23,  0xf4d50d87 );     /*  27  */
    GG(b, c, d, a, x[
8 ], S24,  0x455a14ed );     /*  28  */
    GG(a, b, c, d, x[
13 ], S21,  0xa9e3e905 );     /*  29  */
    GG(d, a, b, c, x[
2 ], S22,  0xfcefa3f8 );     /*  30  */
    GG(c, d, a, b, x[
7 ], S23,  0x676f02d9 );     /*  31  */
    GG(b, c, d, a, x[
12 ], S24,  0x8d2a4c8a );     /*  32  */

    
/*  Round 3  */
    HH(a, b, c, d, x[
5 ], S31,  0xfffa3942 );     /*  33  */
    HH(d, a, b, c, x[
8 ], S32,  0x8771f681 );     /*  34  */
    HH(c, d, a, b, x[
11 ], S33,  0x6d9d6122 );     /*  35  */
    HH(b, c, d, a, x[
14 ], S34,  0xfde5380c );     /*  36  */
    HH(a, b, c, d, x[
1 ], S31,  0xa4beea44 );     /*  37  */
    HH(d, a, b, c, x[
4 ], S32,  0x4bdecfa9 );     /*  38  */
    HH(c, d, a, b, x[
7 ], S33,  0xf6bb4b60 );     /*  39  */
    HH(b, c, d, a, x[
10 ], S34,  0xbebfbc70 );     /*  40  */
    HH(a, b, c, d, x[
13 ], S31,  0x289b7ec6 );     /*  41  */
    HH(d, a, b, c, x[
0 ], S32,  0xeaa127fa );     /*  42  */
    HH(c, d, a, b, x[
3 ], S33,  0xd4ef3085 );     /*  43  */
    HH(b, c, d, a, x[
6 ], S34,  0x4881d05 );     /*  44  */
    HH(a, b, c, d, x[
9 ], S31,  0xd9d4d039 );     /*  45  */
    HH(d, a, b, c, x[
12 ], S32,  0xe6db99e5 );     /*  46  */
    HH(c, d, a, b, x[
15 ], S33,  0x1fa27cf8 );     /*  47  */
    HH(b, c, d, a, x[
2 ], S34,  0xc4ac5665 );     /*  48  */

    
/*  Round 4  */
    II(a, b, c, d, x[
0 ], S41,  0xf4292244 );     /*  49  */
    II(d, a, b, c, x[
7 ], S42,  0x432aff97 );     /*  50  */
    II(c, d, a, b, x[
14 ], S43,  0xab9423a7 );     /*  51  */
    II(b, c, d, a, x[
5 ], S44,  0xfc93a039 );     /*  52  */
    II(a, b, c, d, x[
12 ], S41,  0x655b59c3 );     /*  53  */
    II(d, a, b, c, x[
3 ], S42,  0x8f0ccc92 );     /*  54  */
    II(c, d, a, b, x[
10 ], S43,  0xffeff47d );     /*  55  */
    II(b, c, d, a, x[
1 ], S44,  0x85845dd1 );     /*  56  */
    II(a, b, c, d, x[
8 ], S41,  0x6fa87e4f );     /*  57  */
    II(d, a, b, c, x[
15 ], S42,  0xfe2ce6e0 );     /*  58  */
    II(c, d, a, b, x[
6 ], S43,  0xa3014314 );     /*  59  */
    II(b, c, d, a, x[
13 ], S44,  0x4e0811a1 );     /*  60  */
    II(a, b, c, d, x[
4 ], S41,  0xf7537e82 );     /*  61  */
    II(d, a, b, c, x[
11 ], S42,  0xbd3af235 );     /*  62  */
    II(c, d, a, b, x[
2 ], S43,  0x2ad7d2bb );     /*  63  */
    II(b, c, d, a, x[
9 ], S44,  0xeb86d391 );     /*  64  */

    state[
0 +=  a;
    state[
1 +=  b;
    state[
2 +=  c;
    state[
3 +=  d;

    
/*  Zeroize sensitive information.  */
    memset((
void   * ) x,  0 sizeof  (x));
}

/*  Encodes input (unsigned int) into output (unsigned char). Assumes len is a multiple of 4.  */
static   void  _Encode(unsigned  char   * output, unsigned  int   * input, unsigned  int  len)
{
    unsigned 
int  i, j;

    
for  (i  =   0 , j  =   0 ; j  <  len; i ++ , j  +=   4 ) {
        output[j] 
=  (unsigned  char ) (input[i]  &   0xff );
        output[j 
+   1 =  (unsigned  char ) ((input[i]  >>   8 &   0xff );
        output[j 
+   2 =  (unsigned  char ) ((input[i]  >>   16 &   0xff );
        output[j 
+   3 =  (unsigned  char ) ((input[i]  >>   24 &   0xff );
    }
}

/*  Decodes input (unsigned char) into output (unsigned int). Assumes len is a multiple of 4. */
static   void  _Decode(unsigned  int   * output,  const  unsigned  char   * input, unsigned  int  len)
{
    unsigned 
int  i, j;

    
for  (i  =   0 , j  =   0 ; j  <  len; i ++ , j  +=   4 ) {
        output[i] 
=  ((unsigned  int ) input[j])  |  (((unsigned  int ) input[j  +   1 ])  <<   8 |
                    (((unsigned 
int ) input[j  +   2 ])  <<   16 |  (((unsigned  int ) input[j  +   3 ])  <<   24 );
    }
}

        uuid32.c文件如下:

 

/*  uuid32.c 
   2007-09-15 Last created by cheungmine.
   Partly rights reserved by cheungmine.
*/

#include 
< stdio.h >
#include 
< string .h >

#include 
< time.h >
#include 
< sys / types.h >
#include 
< sys / timeb.h >

#include 
" uuid32.h "
#include 
" md5.h "


#define  MD5_LEN            16
#define  UUID_LEN        36

/*  microsecond per second. 1s=1000000us=1000000000ns */
#define  NSec100_Per_Sec        10000000
#define  USec_Per_Sec        1000000
#define  USec_Per_MSec        1000
#define  NSec_Since_1582        ((uint64)(0x01B21DD213814000))


/* ========================================================================================
                            Private Functions
========================================================================================
*/
static  BOOL isbigendian()
{
    
int  c  =   1 ;
    
return  (  * ((unsigned  char   * & c)  ==   1  ) ?  FALSE: TRUE;
};

static   void  swap_word(  int  size_bytes,  void   *  ptr_word )
{
    
int         i;
    unsigned 
char        temp;
    
for ( i = 0 ; i  <  size_bytes / 2 ; i ++  )
    {
        temp 
=  ((unsigned  char   * ) ptr_word)[i];
        ((unsigned 
char   * ) ptr_word)[i]  =  ((unsigned  char   * ) ptr_word)[size_bytes - i - 1 ];
        ((unsigned 
char   * ) ptr_word)[size_bytes - i - 1 =  temp;
    }
};

static   void  write_word( unsigned  char *  stream, word_t val )
{
    memcpy(stream, 
& val,  2 );
    
if ( isbigendian() ) swap_word(  2 , stream );
};

static   void  write_dword( unsigned  char *  stream, dword_t val )
{
    memcpy(stream, 
& val,  4 );
    
if ( isbigendian() ) swap_word(  4 , stream );
};

static   void   read_word(  const  unsigned  char *  stream, word_t *  val )
{
    memcpy( val, stream, 
2  );
    
if ( isbigendian() )    swap_word(  2 , val );
};

static   void   read_dword(  const  unsigned  char *  stream, dword_t *  val )
{
    memcpy( val, stream, 
4  );
    
if ( isbigendian() )    swap_word(  4 , val );
};

static  BOOL is_xdigit( char  c)
{
    
/*  isxdigit returns a non-zero value if c is a hexadecimal digit (A – F, a – f, or 0 – 9).  */
    
return  ((c >= ' A ' && c <= ' F ' ) || (c >= ' a ' && c <= ' f ' ) || (c >= ' 0 ' && c <= ' 9 ' )) ?  TRUE : FALSE;
};


/*  make a pseudorandom numbel based on current time */
static   int  pseudo_rand()
{
#ifdef _USE_32BIT_TIME_T
    assert(
0 );
#endif

    
struct  _timeb  timebuf;

#pragma  warning(push)    /* C4996 */
#pragma  warning( disable : 4996 )
    _ftime64(
& timebuf);
#pragma  warning(pop)    /* C4996 */
    
    srand((uint32) ((((uint32)timebuf.time
& 0xFFFF ) + (uint32)timebuf.millitm) ^ (uint32)timebuf.millitm));

    
return  rand();
};


/* ========================================================================================
                            Public Functions
========================================================================================
*/

BOOL is_uuid_string(
const   char   * uuid) 
{    
    
static   const   char  fmt[]  =   " xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx " ;
    
int  i;
    assert(uuid 
!=  NULL);
    
for  (i  =   0 ; i  <   sizeof (fmt); i ++ )
        
if  (fmt[i]  ==   ' x ' )
            
if  ( ! is_xdigit(uuid[i]))
                
return  FALSE;
        
else   if  (uuid[i]  !=  fmt[i])
            
return  FALSE;

    
return  TRUE;
}


/* *
 * internal
 * ingroup uuid
 * The thread synchronization lock used to guarantee UUID uniqueness
 * for all the threads running within a process.
 
*/
void  uuid_create(uuid_t *  u) 
{    
    
static  BOOL        initialized  =  FALSE;
    
static  int64    timestamp;
    
static  uint32    advance;
    
static  uint16    clockseq;
    
static  uint16    node_high;
    
static  uint32    node_low;
    int64            time;    
/*  unit of 100ns  */
    uint16            nowseq;
    
int                 r;

    #ifdef _USE_32BIT_TIME_T
        assert(
0 );
    
#endif

    
struct  _timeb  tv;

    assert(u);

#pragma  warning(push)    /* C4996 */
#pragma  warning( disable : 4996 )
    _ftime64(
& tv);
#pragma  warning(pop)    /* C4996 */

    
/*  time is counter of 100ns time interval since Oct.15, 1582 (NOT 1852)  */
    time 
=  ((uint64) tv.time)  *  USec_Per_Sec  +  ((uint64) tv.millitm * USec_Per_MSec);
    time 
=  time  *   10   +  NSec_Since_1582;

    
if  ( ! initialized) 
    {
        timestamp 
=  time;
        advance 
=   0 ;

        r 
=  pseudo_rand();

        clockseq 
=  r  >>   16 ;
        node_high 
=  r  |   0x0100 ;
        
        node_low 
=  pseudo_rand();
        
        initialized 
=  TRUE;
    } 
    
else   if  (time  <  timestamp) 
    {
        timestamp 
=  time;
        advance 
=   0 ;
        clockseq
++ ;
    } 
    
else   if  (time  ==  timestamp) 
    {
        advance
++ ;
        time 
+=  advance;
    } 
    
else  
    {
        timestamp 
=  time;
        advance 
=   0 ;
    }
    nowseq 
=  clockseq;

    assert(u);
    u
-> data1  =  (dword_t) time;
    u
-> data2  =  (word_t) ((time  >>   32 &   0xffff );
    u
-> data3  =  (word_t) (((time  >>   48 &   0x0ffff |   0x1000 );
    write_word(
& (u -> data4[ 6 ]), (word_t) ((nowseq  &   0x3fff |   0x8000 ));    
    write_word(
& (u -> data4[ 4 ]), (word_t) (node_high));                    
    write_dword(
& (u -> data4[ 0 ]), (dword_t) (node_low));            
}

/* *
 * internal
 * ingroup uuid
 * The thread synchronization lock used to guarantee UUID uniqueness
 * for all the threads running within a process.
 
*/
char   * uuid_create_string( void
{
    uuid_t  u;
    uuid_create(
& u);
    
return  uuid_to_string( & u);
}

char   * uuid_to_string( const  uuid_t *   u)
{
    
static   char  uuid_str[UUID_LEN + 1 ];
    
ushort  a,b;
    uint32  c;
    read_word(
& (u -> data4[ 6 ]),  & a);
    read_word(
& (u -> data4[ 4 ]),  & b);
    read_dword(
& (u -> data4[ 0 ]),  & c);

#pragma  warning(push)    /* C4996 */
#pragma  warning( disable : 4996 )
    sprintf(uuid_str, 
" %08lx-%04x-%04x-%04x-%04x%08lx "
                u
-> data1,
                u
-> data2,
                u
-> data3,
                a, b, c);
#pragma  warning(pop)    /* C4996 */
    
return  uuid_str;
}

/* *
 * internal
 * ingroup uuid
 * The predefined namespace UUID. Expressed in binary format
 * to avoid unnecessary conversion when generating name based UUIDs.
 
*/
static   const  unsigned  char  namespace_uuid[]  =  {
        
0x9c 0xfb 0xd9 0x1f 0x11 0x72 0x4a 0xf6 ,
        
0xbd 0xcb 0x9f 0x34 0xe4 0x6f 0xa0 0xfb
};

void   uuid_create_external( const   char   * external, uuid_t *  u) 
{
    MD5_CTX md5;
    unsigned 
char  uuid[ 16 ];    
    
    assert(external 
!=  NULL);

    MD5_init(
& md5);
    MD5_update(
& md5, namespace_uuid,  sizeof (namespace_uuid));
    MD5_update(
& md5, (unsigned  char   * ) external, (unsigned  int ) strlen(external));
    MD5_fini(uuid, 
& md5);

    u
-> data1  =  (dword_t) (uuid[ 0 <<   24   |  uuid[ 1 <<   16   |  uuid[ 2 <<   8   |  uuid[ 3 ]);
    u
-> data2  =  (word_t)  (uuid[ 4 <<   8   |  uuid[ 5 ]);
    u
-> data3  =  (word_t)  (((uuid[ 6 &   0x0f |   0x30 <<   8   |  uuid[ 7 ]);    
    
    
/*  BYTE 6-7  */
    write_word(
& (u -> data4[ 6 ]), (word_t) (((uuid[ 8 &   0x3f |   0x80 <<   8   |  uuid[ 9 ]));        
    
/*  BYTE 4-5  */
    write_word(
& (u -> data4[ 4 ]), (word_t) (uuid[ 10 <<   8   |  uuid[ 11 ]));                        
    
/*  BYTE 0-3  */
    write_dword(
& (u -> data4[ 0 ]), (dword_t) (uuid[ 12 <<   24   |  uuid[ 13 <<   16   |  uuid[ 14 <<   8   |  uuid[ 15 ]));
}

/* *
 * Get timestamp from a UUID
 *
*/
void  uuid_to_timestamp( const  uuid_t *  u, timestamp_t *  t)
{
    int64   time, t2, t3;
    
struct   tm *   p;
    assert(u);

    t2 
=  u -> data2;
    t3 
=  u -> data3;

    time 
=  u -> data1  +  (t2 << 32 +  ((t3 & 0x0fff ) << 48 );         /*  100ns  */
    time 
-=  NSec_Since_1582;

    t
-> tm_fraction  =  ( long )(time % NSec100_Per_Sec);
    
    time 
/=   10 ;
    time 
/=  USec_Per_Sec; 
    
#pragma  warning(push)    /* C4996 */
#pragma  warning( disable : 4996 )
    p 
=  _localtime64( & time);
#pragma  warning(pop)    /* C4996 */
    
    t
-> tm_hour  =  p -> tm_hour;
    t
-> tm_mday  =  p -> tm_mday;
    t
-> tm_min  =  p -> tm_min;
    t
-> tm_mon  =  p -> tm_mon;
    t
-> tm_sec  =  p -> tm_sec;
    t
-> tm_wday  =  p -> tm_wday;
    t
-> tm_yday  =  p -> tm_yday;
    t
-> tm_year  =  p -> tm_year;
}

char *  timestamp_to_string( const  timestamp_t *  time)
{
    
struct  tm t;
    t.tm_hour 
=  time -> tm_hour;
    t.tm_mday 
=  time -> tm_mday;
    t.tm_min 
=  time -> tm_min;
    t.tm_mon 
=  time -> tm_mon;
    t.tm_sec 
=  time -> tm_sec;
    t.tm_wday 
=  time -> tm_wday;
    t.tm_yday 
=  time -> tm_yday;
    t.tm_year 
=  time -> tm_year;

#pragma  warning(push)    /* C4996 */
#pragma  warning( disable : 4996 )
    
return  asctime( & t);
#pragma  warning(pop)    /* C4996 */
}



/* *
 * Compare two UUID's lexically
 *    return
 *      -1   u1 is lexically before u2
 *     0   u1 is equal to u2
 *     1   u1 is lexically after u2
*/
int  uuid_compare( const  uuid_t  * u1,  const  uuid_t  * u2)
{
    
int  i;

#define  CHECK_COMP(f1, f2)  if ((f1) != (f2)) return ((f1) < (f2) ? -1 : 1);
    
    CHECK_COMP(u1
-> data1, u2 -> data1);
    CHECK_COMP(u1
-> data2, u2 -> data2);
    CHECK_COMP(u1
-> data3, u2 -> data3);

    
for (i = 0 ; i < 8 ; i ++ )
        CHECK_COMP(u1
-> data4[i], u1 -> data4[i]);

#undef  CHECK_COMP

    
return   0 ;
}

/* *
 * Compare two UUID's temporally
 *    return
 *      -1   u1 is temporally before u2
 *     0   u1 is equal to u2
 *     1   u1 is temporally after u2
*/
int  uuid_compare_time( const  uuid_t  * u1,  const  uuid_t  * u2)
{    
#define  CHECK_COMP(f1, f2)  if ((f1) != (f2)) return ((f1) < (f2) ? -1 : 1);
    
    CHECK_COMP(u1
-> data1, u2 -> data1);
    CHECK_COMP(u1
-> data2, u2 -> data2);
    CHECK_COMP(u1
-> data3, u2 -> data3);

#undef  CHECK_COMP

    
return   0 ;
}

      好了,到此,所有文件都列出来了,它们是:cdatatype.h、md5.h、uuid32.h、md5.c和uuid32.c。

最后是测试代码:

 

/*  uuidgen.c 
   2007-09-15 Last created by cheungmine.
   All rights reserved by cheungmine.
   C application
*/
#include 
< stdio.h >
#include 
< stdlib.h >
#include 
< string .h >

#include 
" md5.h "
#include 
" uuid32.h "

int  main()
{
    
char   * sign,  * uid;
    uuid_t u, v, x;
    timestamp_t  t;
    
    sign 
=  MD5_sign( " hello world " , (unsigned  int )strlen( " hello world " ));
    printf(
" md5 string digit:%s " , sign);
    
    uuid_create(
& u);
    uid 
=  uuid_to_string( & u);
    printf(
" uuid U to string:{%s} " , uid);

    uuid_create(
& v);
    uid 
=  uuid_to_string( & v);
    printf(
" uuid V to string:{%s} " , uid);
    
    printf(
" uuid compare U with V lexically:%d " , uuid_compare( & u,  & v));

    printf(
" uuid compare V with U temporally:%d " , uuid_compare_time( & v,  & u));


    uid 
=  uuid_create_string();
    printf(
" new uuid string:{%s} " , uid);
        
    uuid_create_external(
" cheungmine " & x);
    uid 
=  uuid_to_string( & x);
    printf(
" new external uuid to string:{%s} " , uid);
        
    uuid_to_timestamp(
& u,  & t);
    printf(
" %s " , timestamp_to_string( & t));
    
    
return   0 ;
}

          以上代码保证正确。请放心使用!

目录
相关文章
|
10月前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
381 1
|
10月前
|
搜索推荐 C语言
【排序算法】快速排序升级版--三路快排详解 + 实现(c语言)
本文介绍了快速排序的升级版——三路快排。传统快速排序在处理大量相同元素时效率较低,而三路快排通过将数组分为三部分(小于、等于、大于基准值)来优化这一问题。文章详细讲解了三路快排的实现步骤,并提供了完整的代码示例。
305 4
|
存储 算法 C语言
"揭秘C语言中的王者之树——红黑树:一场数据结构与算法的华丽舞蹈,让你的程序效率飙升,直击性能巅峰!"
【8月更文挑战第20天】红黑树是自平衡二叉查找树,通过旋转和重着色保持平衡,确保高效执行插入、删除和查找操作,时间复杂度为O(log n)。本文介绍红黑树的基本属性、存储结构及其C语言实现。红黑树遵循五项基本规则以保持平衡状态。在C语言中,节点包含数据、颜色、父节点和子节点指针。文章提供了一个示例代码框架,用于创建节点、插入节点并执行必要的修复操作以维护红黑树的特性。
238 1
|
10月前
|
存储 算法 数据管理
C语言算法复杂度
【10月更文挑战第20天】
97 5
C语言算法复杂度
|
9月前
|
存储 算法 程序员
C 语言递归算法:以简洁代码驾驭复杂逻辑
C语言递归算法简介:通过简洁的代码实现复杂的逻辑处理,递归函数自我调用解决分层问题,高效而优雅。适用于树形结构遍历、数学计算等领域。
|
10月前
|
存储 缓存 算法
C语言在实现高效算法方面的特点与优势,包括高效性、灵活性、可移植性和底层访问能力
本文探讨了C语言在实现高效算法方面的特点与优势,包括高效性、灵活性、可移植性和底层访问能力。文章还分析了数据结构的选择与优化、算法设计的优化策略、内存管理和代码优化技巧,并通过实际案例展示了C语言在排序和图遍历算法中的高效实现。
268 2
|
10月前
|
机器学习/深度学习 算法 数据挖掘
C语言在机器学习中的应用及其重要性。C语言以其高效性、灵活性和可移植性,适合开发高性能的机器学习算法,尤其在底层算法实现、嵌入式系统和高性能计算中表现突出
本文探讨了C语言在机器学习中的应用及其重要性。C语言以其高效性、灵活性和可移植性,适合开发高性能的机器学习算法,尤其在底层算法实现、嵌入式系统和高性能计算中表现突出。文章还介绍了C语言在知名机器学习库中的作用,以及与Python等语言结合使用的案例,展望了其未来发展的挑战与机遇。
208 1
|
10月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
245 1
|
10月前
|
搜索推荐 算法 C语言
【排序算法】八大排序(下)(c语言实现)(附源码)
本文继续学习并实现了八大排序算法中的后四种:堆排序、快速排序、归并排序和计数排序。详细介绍了每种排序算法的原理、步骤和代码实现,并通过测试数据展示了它们的性能表现。堆排序利用堆的特性进行排序,快速排序通过递归和多种划分方法实现高效排序,归并排序通过分治法将问题分解后再合并,计数排序则通过统计每个元素的出现次数实现非比较排序。最后,文章还对比了这些排序算法在处理一百万个整形数据时的运行时间,帮助读者了解不同算法的优劣。
345 7
|
10月前
|
搜索推荐 算法 C语言
【排序算法】八大排序(上)(c语言实现)(附源码)
本文介绍了四种常见的排序算法:冒泡排序、选择排序、插入排序和希尔排序。通过具体的代码实现和测试数据,详细解释了每种算法的工作原理和性能特点。冒泡排序通过不断交换相邻元素来排序,选择排序通过选择最小元素进行交换,插入排序通过逐步插入元素到已排序部分,而希尔排序则是插入排序的改进版,通过预排序使数据更接近有序,从而提高效率。文章最后总结了这四种算法的空间和时间复杂度,以及它们的稳定性。
389 8

热门文章

最新文章