写接口校验昵称长度,前端说最多十个字,后端用 strlen 一量,一个中文昵称直接返回超长。测试同学输入「你好」,strlen 返回 6,两边吵了半天。这不是函数有 bug,是它从来就没打算数字符。

strlen 数的是字节,不是字

C 语言里 strlen 从传入的地址开始,一个个字节往后读,遇到值为 0 的字节停下,返回经过的字节数。它不知道什么是字符,更不知道编码。UTF-8 下一个汉字占三个字节,一个 emoji 可能占四个,于是「你好」得 6,带一个表情的昵称长度会突然跳。

那个值为 0 的字节是终止符

把字符数组当参数传进函数,长度信息就丢了,只剩首地址,所以 C 用值为 0 的字节当结尾标记。这意味着字符串中间不能出现这个字节,二进制数据必须另传长度,否则一定被截断。读文件读到的内容直接当字符串用,就是常见的踩坑场景。

sizeof 和 strlen 别混

char s[32],内容 abc,sizeof(s) 得 32,strlen(s) 得 3

sizeof 在编译期算数组占多少字节,包含结尾那个 0 和后面没用到的空间。数组名传进函数后退化成指针,sizeof 只剩指针本身的 8 字节,跟内容长度毫无关系。在函数内部用 sizeof 算缓冲区大小,几乎必错。

要数字符得换函数

PHP 里 strlen 同样是字节数,数中文字符要用 mb_strlen 并指定编码 UTF-8。JavaScript 的 length 数的是 UTF-16 码元,emoji 会被算成 2,要准确得用 Array.from 转成数组再看长度。Go 的 len 也是字节,数字符要用 utf8.RuneCountInString。

数据库字段长度按什么算

MySQL 的 varchar(10) 在 utf8mb4 下是 10 个字符而不是 10 字节,所以按字符限长和按 strlen 限长会打架。接口层用字节限长、数据库用字符限长,就会出现接口放过、入库报错,或者反过来。两边统一口径,最好都在字符维度校验,emoji 单独做一次额外判断。

遇到超长字符串的实测办法

不确定一个字符串到底多长,别靠数。在浏览器控制台敲一句看 length,在命令行用 wc -m 看字符数、wc -c 看字节数,两个数字一比就知道有没有多字节字符。排查数据库字段被截断的问题,这一步往往直接给出答案。

取舍:只跟英文和协议字段打交道,strlen 又快又准;只要可能碰到中文、emoji,一律换成按字符计数的函数,别在字节长度上做业务判断。