Scanning database...
Tools
Articles

No matches found for ""

View All Results
Developer Lab

UUID in C

Production-ready implementation guide with CSPRNG-backed code snippets.



Generate UUID in C

libuuid is the POSIX standard for UUID generation in C — part of util-linux on Linux. uuid_generate_random() always produces a v4 UUID backed by the OS CSPRNG.

Quick Reference

Function Version Notes Use Case
uuid_generate_random() v4 Always random Recommended — always uses CSPRNG
uuid_generate() v4 or v1 Falls back to v1 May use v1 if /dev/random unavailable
uuid_unparse_lower() any Lowercase output Standard lowercase hyphenated string
uuid_unparse_upper() any Uppercase output Uppercase hyphenated string

Primary Implementation

Production Ready
c snippet
#include <uuid/uuid.h>
#include <stdio.h>

int main(void) {
    uuid_t id;
    char id_str[37]; /* 36 chars + null terminator */

    /* Always use uuid_generate_random for guaranteed v4 */
    uuid_generate_random(id);

    /* Lowercase output (recommended) */
    uuid_unparse_lower(id, id_str);
    printf("%s\n", id_str);
    /* → f47ac10b-58cc-4372-a567-0e02b2c3d479 */

    /* Uppercase output */
    char id_upper[37];
    uuid_unparse_upper(id, id_upper);
    printf("%s\n", id_upper);
    /* → F47AC10B-58CC-4372-A567-0E02B2C3D479 */

    /* Parse an existing UUID string */
    uuid_t parsed;
    if (uuid_parse("f47ac10b-58cc-4372-a567-0e02b2c3d479", parsed) == 0) {
        printf("Valid UUID\n");
    } else {
        printf("Invalid UUID\n");
    }

    /* Compare two UUIDs */
    uuid_t id2;
    uuid_generate_random(id2);
    if (uuid_compare(id, id2) == 0) {
        printf("UUIDs are equal\n");
    }

    return 0;
}

All UUID Versions

UUID v4 — Random (always use this)

c snippet
#include <uuid/uuid.h>

uuid_t id;
char str[37];

/* uuid_generate_random always uses /dev/urandom — guaranteed v4 */
uuid_generate_random(id);
uuid_unparse_lower(id, str);
printf("%s\n", str); /* → "550e8400-e29b-41d4-a716-446655440000" */

UUID v1 — Time-based (legacy)

c snippet
#include <uuid/uuid.h>

uuid_t id;
char str[37];

/* v1: timestamp + MAC address — leaks host info, use only for legacy compat */
uuid_generate_time(id);
uuid_unparse_lower(id, str);
printf("%s\n", str);

Null UUID check

c snippet
#include <uuid/uuid.h>

uuid_t id;
uuid_generate_random(id);

/* Check if UUID is all zeros (nil UUID) */
if (uuid_is_null(id)) {
    fprintf(stderr, "UUID generation failed\n");
}

/* Clear a UUID (set to nil) */
uuid_clear(id);

Real-World Use Cases

1. Linux system daemon — unique instance ID

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

/* Generate a unique instance ID for this daemon run */
char *create_instance_id(void) {
    uuid_t id;
    char *str = malloc(37);
    if (!str) return NULL;

    uuid_generate_random(id);
    uuid_unparse_lower(id, str);
    return str; /* caller must free() */
}

int main(void) {
    char *instance_id = create_instance_id();
    if (!instance_id) {
        fprintf(stderr, "Failed to allocate UUID\n");
        return 1;
    }
    printf("Daemon instance: %s\n", instance_id);
    free(instance_id);
    return 0;
}

2. Embedded C service — unique message ID

c snippet
#include <uuid/uuid.h>
#include <string.h>

typedef struct {
    char message_id[37];
    char payload[256];
    int  payload_len;
} Message;

void init_message(Message *msg, const char *data, int len) {
    uuid_t id;
    uuid_generate_random(id);
    uuid_unparse_lower(id, msg->message_id);
    memcpy(msg->payload, data, len);
    msg->payload_len = len;
}

3. Database client — generate PK before insert

c snippet
#include <uuid/uuid.h>
#include <stdio.h>

/* Generate UUID and format as SQL literal */
void uuid_to_sql(char *out, size_t out_len) {
    uuid_t id;
    char str[37];
    uuid_generate_random(id);
    uuid_unparse_lower(id, str);
    snprintf(out, out_len, "'%s'", str);
}

int main(void) {
    char sql_uuid[41]; /* 37 + 2 quotes + null */
    uuid_to_sql(sql_uuid, sizeof(sql_uuid));
    printf("INSERT INTO orders (id) VALUES (%s);\n", sql_uuid);
    return 0;
}

Common Mistakes

Not allocating enough space for the output buffer

uuid_unparse() writes exactly 36 characters plus a null terminator. Always allocate char str[37] — a buffer of 36 will cause a buffer overflow.

Using uuid_generate() instead of uuid_generate_random()

uuid_generate() may fall back to a time-based v1 UUID if /dev/random is unavailable. Use uuid_generate_random() to guarantee a v4 UUID from /dev/urandom.

Using rand() to build a UUID manually

rand() is not CSPRNG-backed and only provides 15–31 bits of entropy. A manually constructed UUID using rand() is not RFC 4122 compliant and has a high collision probability.

How It Works

uuid_generate_random() reads 16 bytes from /dev/urandom (Linux) or the platform CSPRNG, then sets the version bits (4) and variant bits (RFC 4122) in the uuid_t array.

uuid_t is defined as unsigned char[16] — a 16-byte array on the stack. uuid_unparse_lower() formats it as a 36-character lowercase hyphenated string.

Output Formats

uuid_unparse_lower(id, str)

f47ac10b-58cc-4372-a567-0e02b2c3d479

uuid_unparse_upper(id, str)

F47AC10B-58CC-4372-A567-0E02B2C3D479

uuid_t — raw bytes

unsigned char[16]

Best Practices

Always use uuid_generate_random() — never uuid_generate() for security-sensitive IDs.

Always allocate char str[37] for the output buffer — 36 chars + null terminator.

Use uuid_unparse_lower() for consistent lowercase output.

Performance

libuuid generates roughly 1–5 million UUIDs/second. The bottleneck is the /dev/urandom read syscall.

uuid_t is a 16-byte stack-allocated array — zero heap allocation per UUID. The string formatting (uuid_unparse) writes to a caller-provided buffer.

Installation

# Debian/Ubuntu
apt install uuid-dev

# RHEL/CentOS/Fedora
yum install libuuid-devel
# Compile with -luuid
gcc myapp.c -luuid -o myapp

On macOS, libuuid is part of the system SDK — no install needed. Link with -framework CoreFoundation or use the POSIX-compatible header.

Security

Entropy source: /dev/urandom on Linux/macOS. uuid_generate_random() always uses the CSPRNG — cryptographically secure.

Suitable for session tokens and security-sensitive IDs. Avoid uuid_generate_time() for security use — it embeds the MAC address.