近期在搞一个 IP地址配置到内核 的问题。
命令行输入IP地址给内核,我的问题是如何确认这个IP地址的格式是正确的,比如我输入一个 “1.2.300.x” 会怎样? 比如我输入 “1.2.3.a”
,如果把“a” 解释成10是对还是不对…诸如此类。
对于这种判断,要是真要写代码,我是讨厌的。几年来时不时就要写这种,网上也有很多现成的东西,但基本上看起来都不优雅。
我也曾看过一些Linux内核,glibc的实现,但基本上都是丑陋不堪。这种涉及到模式匹配的代码,是不是就一定要丑陋不堪呢?我想是的。
没人能用低级语言比如C,汇编这种,把这种代码写优雅!没人!
如果不用低级语言,那么用高级的试试看,比如在bash脚本里去判断呢。
我恶心透了正则表达式,这种老鳖疯狗都会写的东西,实在是太复杂而不是太简单。你让一个婴儿在电脑上写一段能运行的代码,我敢保证如果可以,那么写出来的一定是正则表达式,你同意吗?
正确的做法是实现一个状态机,然后逐个字符逐个字符的去解析,然后抽取点分十进制…唉,对于不会编程的我,这实在是太复杂!
下面是一个用go语言比葫芦画瓢写出来的:
func InetAton(ip string) uint32 { var addr uint32 if ip == "" { return 1234 }
bits:= strings.Split(ip, ".") for i := range bits { if isNotNumeric(bits[i]) {
return 1234 } b, _ := strconv.Atoi(bits[i]) if b > 255 || b < 0 { return 1234 }
addr+= uint32(b) << (8*(3-uint32(i))) } return addr }
这段代码有问题吗?
问题大了去了。比方说返回值就是问题。
我们知道IPv4地址占据整个32位4G的空间,和32位系统内存一样,从0x00000000到0xffffffff都有解释,那么如果我们的转换函数返回一个uint32的类型,如何代码转换错误呢?
魔术字肯定是不行的,因为即便是小概率,魔术字也有可能代表一个合法的IP地址而不是错误!这个时候,就只能用类似C库里面的errno这种机制,但是这种机制又要考虑线程安全性,真是越考虑越复杂!
我知道atoi这个函数就有这样的问题,甚至errno都拯救不了它。请看下面的代码:
#include <stdlib.h> #include <stdio.h> int main() { printf("%d\n", atoi("a"));
perror("atoi-a printf"); atoi("a"); perror("atoi-a"); printf("%d\n", atoi("x"));
printf("%d\n", atoi("-1")); printf("%d\n", atoi("0")); }
这该怎么办?
热门工具 换一换