在網絡編程中,IP地址合法性判斷、子網掩碼有效性驗證、IP與掩碼組合合法性檢查以及兩個IP是否屬於同一子網,是基礎且高頻的需求。本文提供一套基於標準 socket API 的 C 語言實現,支持 IPv4,代碼可移植至 Linux/Windows 平台。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#ifdef _WIN32
#include <Winsock2.h>
#pragma comment(lib, "ws2_32.lib")
#else
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#endif
typedef uint32_t IPAddr; // 網絡字節序
// 判斷 IP 地址是否合法(排除全0、全1、組播、保留地址等簡化邏輯)
int netIpIsValid(IPAddr ip) {
struct in_addr addr = { .s_addr = ip };
// inet_ntoa 返回靜態緩衝區,非線程安全,僅演示用
const char* str = inet_ntoa(addr);
IPAddr check = inet_addr(str);
return (check != INADDR_NONE && check != 0 && check != 0xFFFFFFFF);
}
// 判斷子網掩碼是否合法(必須是連續的1後跟連續的0)
int netMaskIsValid(IPAddr mask) {
if (!netIpIsValid(mask)) return 0;
uint32_t hmask = ntohl(mask);
// 技巧:合法掩碼 hmask | (hmask - 1) == 0xFFFFFFFF
return ((hmask | (hmask - 1)) == 0xFFFFFFFF);
}
// 判斷 IP 與掩碼組合是否合法(排除網絡地址、廣播地址、子網號全0/全1等)
int netMaskAndIpIsValid(IPAddr ip, IPAddr mask) {
if (!netIpIsValid(ip) || !netMaskIsValid(mask)) return 0;
uint32_t hip = ntohl(ip);
uint32_t hmask = ntohl(mask);
uint32_t hostPart = hip & ~hmask;
// 主機部分全0(網絡地址)或全1(廣播地址)非法
if (hostPart == 0 || hostPart == ~hmask) return 0;
// 簡化的 A/B/C 類默認掩碼檢查(實際應用中 CIDR 無類別,此邏輯僅作演示)
uint8_t firstOctet = hip >> 24;
if (firstOctet < 128) { // A類
if (hmask < 0xFF000000) return 0;
} else if (firstOctet < 192) { // B類
if (hmask < 0xFFFF0000) return 0;
} else if (firstOctet < 224) { // C類
if (hmask < 0xFFFFFF00) return 0;
} else return 0; // D/E 類不作為主機地址
// 子網號非全0/全1(RFC 1009 老規範,現代 CIDR 已廢棄,保留兼容)
uint32_t subnetPart = hip & hmask;
if (subnetPart == 0 || subnetPart == hmask) return 0;
return 1;
}
// 判斷兩個 IP 是否在同一子網(給定掩碼)
int netIPAndSubnetValid(IPAddr ip1, IPAddr ip2, IPAddr mask) {
if (!netMaskAndIpIsValid(ip1, mask) || !netMaskAndIpIsValid(ip2, mask)) return 0;
return (ip1 & mask) == (ip2 & mask);
}
int main() {
// 測試數據:網絡字節序(大端)
IPAddr ip1 = inet_addr("192.168.10.65"); // 0x410AA8C0
IPAddr mask1 = inet_addr("255.255.255.192"); // 0xC0FFFFFF
printf("IP: %s, Mask: %s -> %s\n",
inet_ntoa(*(struct in_addr*)&ip1),
inet_ntoa(*(struct in_addr*)&mask1),
netMaskAndIpIsValid(ip1, mask1) ? "Valid" : "Invalid");
// 同子網測試
IPAddr ipA = inet_addr("192.168.1.10");
IPAddr ipB = inet_addr("192.168.1.20");
IPAddr mask = inet_addr("255.255.255.0");
printf("Same subnet: %s\n", netIPAndSubnetValid(ipA, ipB, mask) ? "Yes" : "No");
return 0;
}
htonl/ntohl、htons/ntohs、inet_addr/inet_ntoa 進行轉換。注意 inet_ntoa 返回靜態緩衝區,多線程環境下需用 inet_ntop。(mask | (mask-1)) == 0xFFFFFFFF 判斷是否為連續 1 後跟連續 0。if (func()) 而非 if (func() == TRUE)。inet_pton/inet_ntop 替代舊 API,支持 IPv6 且線程安全。這套代碼涵蓋了 IPv4 地址校驗的核心邏輯,可直接集成到網絡設備配置、防火牆規則解析、SDN 控制器等項目中。