Subnet / CIDR Calculator — C source
Compute IPv4 subnet details from a CIDR block - network, broadcast, host range, netmask, wildcard, host count, IP class, and private-range detection. Split a block into smaller subnets, all in your browser.
This is the C implementation — the same logic the interactive tool runs, in a shareable, citable form.
/* subnet-cidr — IPv4 subnet/CIDR math: dotted-quad ⇄ uint32, full subnet details (network, broadcast, hosts, class, private), CIDR splitting. Language: C (C11, stdlib only). Port of src/lib/subnet-cidr.ts — same logic as this dir's python.py / go.go; invalid input reports failure instead of throwing. */
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
typedef struct { char network[16], broadcast[16], first_host[16], last_host[16]; uint64_t hosts; int prefix; char ip_class; bool is_private; } Details;
static bool all_digits(const char *s, size_t n) /* the TS /^\d+$/ test */
{
for (size_t i = 0; i < n; i++) if (s[i] < '0' || s[i] > '9') return false;
return n > 0;
}
static bool ip_to_int(const char *ip, uint32_t *out) /* "a.b.c.d" → uint32 */
{
uint32_t result = 0; int octets = 0; const char *p = ip;
while (true) { /* split on '.', consuming exactly four digit groups */
const char *dot = strchr(p, '.');
size_t len = dot ? (size_t)(dot - p) : strlen(p);
if (!all_digits(p, len)) return false;
long v = 0; /* decimal on purpose — no octal autodetect */
for (size_t i = 0; i < len; i++) v = v * 10 + (p[i] - '0');
if (v > 255) return false;
result = result * 256 + (uint32_t)v;
octets++;
if (!dot) break;
p = dot + 1;
}
return (*out = octets == 4 ? result : 0), octets == 4;
}
static void int_to_ip(uint32_t v, char buf[16]) { sprintf(buf, "%u.%u.%u.%u", (v >> 24) & 255, (v >> 16) & 255, (v >> 8) & 255, v & 255); }
static uint32_t mask_from_prefix(int p) { return p == 0 ? 0 : 0xFFFFFFFFu << (32 - p); }
static bool subnet_details(const char *cidr, Details *d) /* "ip/prefix" → full block info */
{
const char *slash = strchr(cidr, '/');
if (!slash || strchr(slash + 1, '/')) return false; /* exactly one slash */
if (!all_digits(slash + 1, strlen(slash + 1))) return false;
long prefix = 0;
for (const char *q = slash + 1; *q; q++) prefix = prefix * 10 + (*q - '0');
size_t ip_len = (size_t)(slash - cidr);
char ip[32];
if (prefix > 32 || ip_len >= sizeof ip) return false;
memcpy(ip, cidr, ip_len); ip[ip_len] = '\0';
uint32_t ip_int;
if (!ip_to_int(ip, &ip_int)) return false;
uint32_t mask = mask_from_prefix((int)prefix), wildcard = ~mask;
uint32_t network = ip_int & mask, broadcast = network | wildcard;
uint32_t first = prefix >= 31 ? network : network + 1; /* /31,/32: no host split */
uint32_t last = prefix >= 31 ? broadcast : broadcast - 1;
uint64_t hosts = prefix >= 32 ? 1 : prefix == 31 ? 2 : ((uint64_t)1 << (32 - prefix)) - 2;
int o1 = (network >> 24) & 255, o2 = (network >> 16) & 255;
d->ip_class = o1 < 128 ? 'A' : o1 < 192 ? 'B' : o1 < 224 ? 'C' : '-'; /* D/E → '-' */
d->is_private = o1 == 10 || (o1 == 172 && o2 >= 16 && o2 <= 31) || (o1 == 192 && o2 == 168);
int_to_ip(network, d->network); int_to_ip(broadcast, d->broadcast);
int_to_ip(first, d->first_host); int_to_ip(last, d->last_host);
d->hosts = hosts; d->prefix = (int)prefix;
return true;
}
static int split_subnet(const char *cidr, int new_prefix, char out[][20], int max) /* 2^(np-p) children */
{
Details d;
if (!subnet_details(cidr, &d) || new_prefix < d.prefix || new_prefix > 32) return 0;
uint32_t network, block = 1u << (32 - new_prefix);
int count = 1 << (new_prefix - d.prefix);
ip_to_int(d.network, &network);
for (int i = 0; i < count && i < max; i++) {
char ip[16]; int_to_ip(network + (uint32_t)i * block, ip);
snprintf(out[i], 20, "%s/%d", ip, new_prefix);
}
return count;
}
int main(void)
{
Details d;
if (subnet_details("192.168.1.100/24", &d))
printf("%s/24 net=%s bcast=%s hosts=%llu class=%c private=%s\n", d.network, d.network, d.broadcast, (unsigned long long)d.hosts, d.ip_class, d.is_private ? "yes" : "no");
char kids[8][20];
int n = split_subnet("192.168.1.0/24", 26, kids, 8);
for (int i = 0; i < n; i++) printf(" split /26 → %s\n", kids[i]);
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →