Mac地址合法格式为12位十六进制字符,分隔符仅限冒号、短横线或无分隔,大小写不敏感,禁止空格及G–Z等非法字符;IEEE 802标准不认可点号分隔。

Mac地址的合法格式到底长什么样
Mac地址必须是12位十六进制字符,通常以冒号或短横线分隔成6组,每组2位(如 00:1A:2B:3C:4D:5E 或 00-1A-2B-3C-4D-5E),也允许无分隔符(001A2B3C4D5E)。大小写不敏感,但不能含空格、中文、字母G–Z等非法字符。
注意:有些设备会用点号分隔(Cisco风格,如 001A.2B3C.4D5E),但标准IEEE 802只认可冒号/短横线/无分隔三种形式。是否支持点号取决于你的业务需求,不是“合法”与否的技术硬性要求。
用 std::regex 快速验证(C++11及以上)
正则最直观,但要注意编译器对 std::regex 的实现差异——MSVC 支持较好,GCC 早期版本(libstdc++ ≤ 9)的 std::regex 有 bug,可能匹配失败或崩溃。生产环境建议加运行时检测或改用手动解析。
推荐正则表达式:
立即学习“C++免费学习笔记(深入)”;
^[0-9A-Fa-f]{2}([:-])[0-9A-Fa-f]{2}(\1[0-9A-Fa-f]{2}){4}$
说明:
-
^[0-9A-Fa-f]{2}:开头两个十六进制字符 -
([:-]):捕获第一个分隔符(冒号或短横线)到\1 -
(\1[0-9A-Fa-f]{2}){4}:确保后面5组都用**同一个分隔符**,避免00:1A-2B:3C-4D:5E这种混用 - 结尾
$防止尾部多出字符
示例代码片段:
std::string mac = "00:1A:2B:3C:4D:5E";
std::regex re(R"(^[0-9A-Fa-f]{2}([:-])[0-9A-Fa-f]{2}([0-9A-Fa-f]{2}){4}$)");
bool valid = std::regex_match(mac, re);
手写解析更稳,且能提取字节
正则方便但黑盒,调试难;手写解析逻辑清晰、易调试、可顺便转成 std::array<uint8_t></uint8_t> 供后续使用。
关键步骤:
- 先用
erase或遍历跳过分隔符,只保留12个十六进制字符 - 检查长度是否恰好为12
- 逐字符判断是否在
'0'–'9'、'A'–'F'、'a'–'f'范围内 - 用
std::stoi(s.substr(i,2), nullptr, 16)转字节(注意异常捕获)
容易踩的坑:
- 没跳过空格导致
" 00:1A:..."失败 → 建议先std::string::erase所有空白 - 用
std::toupper逐字符转大写再比对,比写两套判断更简洁 - 忘记检查字符串总长,导致
"001A2B3C4D5E12"(14位)被误判
要不要处理广播地址和组播地址
技术上,FF:FF:FF:FF:FF:FF(广播)和 01:00:5E:xx:xx:xx(IPv4组播)都是合法Mac地址,只是语义特殊。如果你的场景需要过滤掉它们(比如只接受单播设备),得额外加判断:
- 广播:所有6字节全为
0xFF - 本地管理地址:第1字节最低位为1(即
mac[0] & 1为真)→ 表示非厂商烧录地址 - 组播IPv4:前3字节为
{0x01, 0x00, 0x5E}
这些判断应在格式校验通过后进行,否则无效输入可能引发越界访问。
真正麻烦的是边缘情况:全零地址(00:00:00:00:00:00)在某些协议中非法,但语法合法;虚拟机或容器常生成随机MAC,只要格式对就得接受。业务规则永远比语法更复杂。


















