关于 strlen 的小迷惑

首先,说明一下,我不是一个 C 程序猿,也不是一个 C++程序猿,我从入门开始真正学习的编程语言以及正经用过的变成语言,也就是 Java 和 C#,虽然我对其他的语言都非常感兴趣,同时也写过一些 Python 的脚本和 C 的代码(主要集中在 JNI)。

由于这些年来的编程习惯,我认为字符串都应该会有自动获取其长度的方法,在前几天的工作中就碰到需要使用这个方法的场景了。由于我对 strlen() 使用的不慎,导致程序输出时而正确时而错误,最终定位到是因为使用 strlen() 方法获取字符串长度在多次执行后的输出不等,导致程序出现了不可控的情况。

那么是否是因为 strlen() 方法的问题呢,我自己首先十分肯定绝对不会是这个方法的问题,这些方法在时间和实践中都尼玛得到过太多的验证,且看 Linux 中的实现:
[c light=”true”]
#ifndef __HAVE_ARCH_STRLEN
/**
* strlen – Find the length of a string
* @s: The string to be sized
*/
size_t strlen(const char * s)
{
const char *sc;

for (sc = s; *sc != '\0'; ++sc)
/* nothing */;
return sc – s;
}
#endif
[/c]
这么简洁的实现,多么漂亮啊。肿么可能会出错捏?好吧,实际的应用场景是我需要将一个从 C#运行时托管层将一个 byte 数组传入 Native 层,在 Native 层面做一些操作的时候呢,我直接使用了 strlen() 函数来确认当前 byte 数组的长度,尼玛脑残啊。托管层 byte 数组虽说可以认为是 Native 层的 unsigned char 数组,但是我并木有意识到 C 层的字符串都是需要’\0’ 来作为终止符滴,显然从托管层传入的数组中不会自行添加这个到数组中。所以才会出现偶尔内存中该数组后面确实没有任何值,那么 strlen() 函数在刚好读取到数组后的值为空时,那么其长度刚好正确,在某些时候该数组后连续的内存地址中并不为空,那么 strlen() 就会返回一个错误的长度,而我的逻辑代码又依赖于该长度,所以你只到的,Just Fucked Up!

所以在托管层申请的内存,传入 Native 层面时,一定要注意两个平台下对某些概念处理的不一致,否则到时候又得吃自己的狗屎了。WTF。