What is GUID and how to use it

Uwaga! Informacje na tej stronie mają ponad 5 lat. Nadal je udostępniam, ale prawdopodobnie nie odzwierciedlają one mojej aktualnej wiedzy ani przekonań.

# What is GUID and how to use it

Thu
16
Jul 2009

There are many ways to identify objects in a collection. One of them is to keep direct pointers to objects. Another way is to simply index their positions in an array. We can make user see only some strange indirect "handles" without any obvious meaning, like HWND or FILE*. We can also give objects string names or some numeric identifiers. SQL databases often use integer number to identify record in a table and new identifiers are generated as subsequent numbers. Another solution is to use GUIDs.

GUID means Globally Unique Identifier and it is a kind of general purpose, 128-bit numeric identifier. GUIDs are generated from some random data. We can be sure about their uniqueness in any context because of their size, as 2^128 possible values is more than stars in the whole observable universe :) That's why they are called "globally unique".

We could just generate 128 bits of data from any good pseudorandom number generator and call it good identifiers, but to standardize this idea, they have created standard - RFC4122 (it's actually UUID, but let's ignore the difference). This standard says how to express GUIDs as strings, made of hexadecimal numbers separated by dashes (for example "f81d4fae-7dec-11d0-a765-00a0c91e6bf6"). You can find such GUIDs everywhere. For example, run "regedit.exe" and look into key HKEY_CLASSES_ROOT\CLSID or run your Visual C++ and run command Tools / Create GUID from the main menu.

The standard also defines bit structure of the UUID and algorithms to generate it. There are several possible algorithms. Some of them use system time or even network card MAC address. The simplest one is version 4 algorithm, which uses only random number generator. Some of bits have special meaning and code algorithm which have been used to generate particular GUID.

Here is my code in C++ defining GUID structure and the algorithm to generate it.

// HPP file

class MyGUID
{
public:
  static const MyGUID NIL;

  static int Cmp(const MyGUID &v1, const MyGUID &v2);

  // Creates uninitialized
  MyGUID() { }
  MyGUID(
    unsigned char v0, unsigned char v1, unsigned char v2, unsigned char v3,
    unsigned char v4, unsigned char v5, unsigned char v6, unsigned char v7,
    unsigned char v8, unsigned char v9, unsigned char v10, unsigned char v11,
    unsigned char v12, unsigned char v13, unsigned char v14, unsigned char v15);
  void Set(const MyGUID &v) { *this = v; }

  const unsigned char * AccessData() const { return Data; }
  unsigned char * AccessData() { return Data; }

  const unsigned char & operator [] (unsigned i) const { return Data[i]; }
  unsigned char & operator [] (unsigned i) { return Data[i]; }

  bool operator == (const MyGUID &v) const { return Cmp(*this, v) == 0; }
  bool operator != (const MyGUID &v) const { return Cmp(*this, v) != 0; }
  bool operator <  (const MyGUID &v) const { return Cmp(*this, v) <  0; }
  bool operator >  (const MyGUID &v) const { return Cmp(*this, v) >  0; }
  bool operator <= (const MyGUID &v) const { return Cmp(*this, v) <= 0; }
  bool operator >= (const MyGUID &v) const { return Cmp(*this, v) >= 0; }

  void ToString(char *out) const; // Buffer have to be at least 37 chars long.
  bool FromString(const char *s);

  void GenerateVersion4();

private:
  // From least to most significant bytes, Data[0] is LSB.
  unsigned char Data[16];
};

// CPP file

const MyGUID MyGUID::NIL =
  MyGUID(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);

int MyGUID::Cmp(const MyGUID &v1, const MyGUID &v2)
{
  int v;
  for (unsigned i = 16; i--; )
  {
    v = (int)v1.Data[i] - (int)v2.Data[i];
    if (v != 0) return v;
  }
  return 0;
}

MyGUID::MyGUID(
  unsigned char v0, unsigned char v1, unsigned char v2, unsigned char v3,
  unsigned char v4, unsigned char v5, unsigned char v6, unsigned char v7,
  unsigned char v8, unsigned char v9, unsigned char v10, unsigned char v11,
  unsigned char v12, unsigned char v13, unsigned char v14, unsigned char v15)
{
  Data[ 0] = v0;  Data[ 1] = v1;  Data[ 2] =  v2; Data[ 3] = v3;
  Data[ 4] = v4;  Data[ 5] = v5;  Data[ 6] =  v6; Data[ 7] = v7;
  Data[ 8] = v8;  Data[ 9] = v9;  Data[10] = v10; Data[11] = v11;
  Data[12] = v12; Data[13] = v13; Data[14] = v14; Data[15] = v15;
}

void MyGUID::ToString(char *out) const
{
  sprintf_s(out, 37,
    "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
    (int)Data[15], (int)Data[14], (int)Data[13], (int)Data[12],
    (int)Data[11], (int)Data[10], (int)Data[ 9], (int)Data[ 8],
    (int)Data[ 7], (int)Data[ 6], (int)Data[ 5], (int)Data[ 4],
    (int)Data[ 3], (int)Data[ 2], (int)Data[ 1], (int)Data[ 0] );
}

void MyGUID::GenerateVersion4()
{
  for (unsigned i = 0; i < 16; i++)
    Data[i] = (unsigned char)rand();

  Data[7] = Data[7] & 0x3F | 0x80;
  Data[9] = Data[9] & 0x0F | 0x40;
}

bool MyGUID::FromString(const char *s)
{
  int ints[16];
  int R = sscanf_s(s,
    "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
    &ints[15], &ints[14], &ints[13], &ints[12],
    &ints[11], &ints[10], &ints[ 9], &ints[ 8],
    &ints[ 7], &ints[ 6], &ints[ 5], &ints[ 4],
    &ints[ 3], &ints[ 2], &ints[ 1], &ints[ 0] );
  if (R != 16) return false;
  for (unsigned i = 0; i < 16; i++)
    Data[i] = (unsigned char)ints[i];
  return true;
}

Comments | #c++ #algorithms Share

Comments

STAT NO AD
[Stat] [STAT NO AD] [Download] [Dropbox] [pub] [Mirror] [Privacy policy]
Copyright © 2004-2019