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 — C++ (20) port: IPv4 subnet/CIDR math (dotted-quad ⇄ uint32, subnet details, CIDR splitting). Port of src/lib/subnet-cidr.ts — same logic as this dir's python.py / go.go; validation failures surface as std::optional nullopt.
#include <cstdint>
#include <cstdio>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
namespace subnet_cidr {
bool all_digits(std::string_view s) // the TS /^\d+$/ check — no signs, no hex, no empty
{
if (s.empty()) return false;
for (char c : s) if (c < '0' || c > '9') return false;
return true;
}
std::optional<uint32_t> ip_to_int(std::string_view ip) // "a.b.c.d" → uint32
{
uint32_t result = 0; int octets = 0; size_t start = 0;
while (true) {
size_t dot = ip.find('.', start);
auto part = ip.substr(start, dot == std::string_view::npos ? ip.size() - start : dot - start);
if (!all_digits(part) || part.size() > 3) return std::nullopt;
int v = 0; // decimal on purpose — no octal autodetect
for (char c : part) v = v * 10 + (c - '0');
if (v > 255) return std::nullopt;
result = result * 256 + static_cast<uint32_t>(v);
octets++;
if (dot == std::string_view::npos) break;
start = dot + 1;
}
return octets == 4 ? std::optional{result} : std::nullopt;
}
std::string int_to_ip(uint32_t v)
{
return std::to_string(v >> 24) + "." + std::to_string((v >> 16) & 255) + "." + std::to_string((v >> 8) & 255) + "." + std::to_string(v & 255);
}
uint32_t mask_from_prefix(int p) { return p == 0 ? 0 : 0xFFFFFFFFu << (32 - p); }
struct Details {
std::string network, broadcast, first_host, last_host; uint64_t host_count; int prefix; char ip_class; bool is_private;
};
std::optional<Details> subnet_details(std::string_view cidr) // "ip/prefix" → full block info
{
size_t slash = cidr.find('/');
if (slash == std::string_view::npos || cidr.find('/', slash + 1) != std::string_view::npos) return std::nullopt;
auto prefix_str = cidr.substr(slash + 1);
if (!all_digits(prefix_str) || prefix_str.size() > 2) return std::nullopt;
int prefix = 0; // decimal on purpose — no octal autodetect
for (char c : prefix_str) prefix = prefix * 10 + (c - '0');
auto ip = ip_to_int(cidr.substr(0, slash));
if (prefix > 32 || !ip) return std::nullopt;
uint32_t mask = mask_from_prefix(prefix);
uint32_t network = *ip & mask, broadcast = network | ~mask;
// /31 (point-to-point) and /32 (single host) have no host/broadcast split.
uint32_t first = prefix >= 31 ? network : network + 1;
uint32_t last = prefix >= 31 ? broadcast : broadcast - 1;
uint64_t hosts = prefix >= 32 ? 1 : prefix == 31 ? 2 : (uint64_t{1} << (32 - prefix)) - 2;
uint32_t o1 = network >> 24, o2 = (network >> 16) & 255;
char klass = o1 < 128 ? 'A' : o1 < 192 ? 'B' : o1 < 224 ? 'C' : '-'; // D/E → '-'
bool priv = o1 == 10 || (o1 == 172 && o2 >= 16 && o2 <= 31) || (o1 == 192 && o2 == 168);
return Details{int_to_ip(network), int_to_ip(broadcast), int_to_ip(first), int_to_ip(last), hosts, prefix, klass, priv};
}
std::vector<std::string> split_subnet(std::string_view cidr, int new_prefix) // 2^(np-p) children
{
auto d = subnet_details(cidr);
if (!d || new_prefix < d->prefix || new_prefix > 32) return {};
uint32_t network = *ip_to_int(d->network), block = 1u << (32 - new_prefix);
int count = 1 << (new_prefix - d->prefix);
std::vector<std::string> out; out.reserve(count);
for (int i = 0; i < count; i++) out.push_back(int_to_ip(network + uint32_t(i) * block) + "/" + std::to_string(new_prefix));
return out;
}
} // namespace subnet_cidr
int main()
{
using namespace subnet_cidr;
if (auto d = subnet_details("192.168.1.100/24"))
std::printf("192.168.1.100/24 net=%s bcast=%s first=%s last=%s hosts=%llu class=%c private=%s\n",
d->network.c_str(), d->broadcast.c_str(), d->first_host.c_str(), d->last_host.c_str(), (unsigned long long)d->host_count, d->ip_class, d->is_private ? "yes" : "no");
for (const auto &kid : split_subnet("192.168.1.0/24", 26)) std::printf(" split /26 → %s\n", kid.c_str());
}
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 →