Developer Lab · C
Generate UUID in C
libuuid is the de facto 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
#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)
#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)
#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
#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
#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
#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
#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, Performance, and Security
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.
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.
Installation
libuuid (uuid_generate)
# Debian/Ubuntu
apt install uuid-dev
# RHEL/CentOS/Fedora
yum install libuuid-devel# Compile with -luuid
gcc myapp.c -luuid -o myappOn macOS, the uuid/uuid.h functions ship with the system C library - no install and no extra linker flags needed.
Frequently Asked Questions
How do I generate a UUID in C?
libuuid is the de facto standard for UUID generation in C, part of util-linux on Linux. Include the uuid/uuid.h header, then uuid_generate_random() fills a uuid_t with a v4 UUID from the OS CSPRNG and uuid_unparse() converts it to a string. Link against -luuid when compiling.
Is uuid_generate() cryptographically secure?
Yes. uuid_generate() uses the platform CSPRNG (operating system secure random source), suitable for session tokens, API keys, and idempotency keys. Do not use non-cryptographic random sources for security-sensitive identifiers.
What is the difference between UUID v4 and v7 in C?
UUID v4 (uuid_generate() or equivalent) is fully random and not sortable. UUID v7 embeds a millisecond timestamp for chronological sorting (RFC 9562). Use v4 for general-purpose IDs; use v7 for database primary keys at scale.
Do I need to install a package for UUID generation in C?
A package or library install may be required. See the Installation section for the recommended approach in C.
How do I validate a UUID string in C?
Use the platform's UUID parse/validation function, or test against the RFC 4122 regex: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i. Always validate external input at API boundaries.
Should I use UUIDs as database primary keys in C applications?
UUIDs work well as primary keys for distributed systems. Prefer native UUID/BINARY(16) column types over VARCHAR(36). For very large tables, consider UUID v7 for better B-tree insert locality.
Can I generate UUIDs in C without a network connection?
Yes. UUID generation uses local OS entropy sources and does not require network access. Each call is independent and thread-safe on modern platforms.
What output formats are available in C?
The standard hyphenated lowercase string (36 chars) is the default. Most APIs also support 32-char hex (no hyphens) and 16-byte binary formats. Use string format for APIs and binary for database storage.
What RFC standards apply to C UUID generation?
Version 4 UUIDs follow RFC 4122. UUID v7 follows RFC 9562 (May 2024). Ensure your chosen method produces compliant version and variant bits.
When should I avoid UUID v1?
Avoid UUID v1 in security-sensitive contexts - it embeds MAC address and timestamp information. Prefer v4 (uuid_generate() or equivalent) unless you need legacy Cassandra timeuuid compatibility.
Key definitions
- UUID
- 128-bit universally unique identifier, usually shown as 36 hex characters with hyphens.
- CSPRNG
- Cryptographically secure pseudo-random number generator - the entropy source behind secure UUID generation.
- RFC 4122
- IETF standard defining UUID versions 1 through 5. Version 4 is random.
- RFC 9562
- IETF standard adding UUID versions 6, 7, and 8. Version 7 is time-ordered.