操作std::string时strlen与size()结果不一致问题咨询
这种情况的核心问题是你的std::string对象的内部结构已经被非法内存操作破坏了,导致它维护的长度信息和实际内存中的内容完全脱节,同时还触发了非法内存访问的未定义行为。
为什么会出现size()和strlen结果不一致?
先给你理清楚两者的本质区别:
std::string::size()返回的是对象内部主动维护的长度值(通常是一个成员变量),它不会去扫描内存找'\0',直接返回这个预存的数值。如果这个数值被错误修改成了0,那size()就会返回0,不管缓冲区里有没有内容。strlen()是C标准库函数,它的逻辑是从传入的指针开始,逐个字节扫描,直到遇到第一个'\0'才停止计数。如果你的std::string内部缓冲区后面的内存(可能是越界的、不属于这个string的内存)刚好有1500个非'\0'的字符,然后才出现'\0',那strlen就会返回1500——这已经是非法访问不属于你这个string的内存了,属于严重的未定义行为。
结合你的代码里的void strRet(void* data)函数,大概率是你在这个函数里把void*直接当成了普通的字符缓冲区来操作:比如直接往里面写了1500个字符,但完全没有更新std::string的内部长度,甚至可能越界写入破坏了std::string的内部结构(比如把存储长度的成员变量改成了0)。毕竟std::string不是简单的字符数组,它有自己的内部结构(比如长度、容量、缓冲区指针这些成员),用void*直接操作很容易把它搞坏。
怎么解决这个问题?
给你几个针对性的方案:
放弃用
void*传递std::string,直接用引用/指针
这是最安全的方式,直接让函数接收std::string的引用,这样你可以用标准的string方法修改它,内部结构会自动维护:void strRet(std::string& data) { // 比如要写入1500个字符,用assign、append等方法 data.assign(1500, 'a'); // 示例:填充1500个'a' // 或者直接用data = "...",或者循环写入都可以 }如果必须用
void*(比如兼容C接口),要正确转换并操作
如果你因为某些原因必须用void*,那一定要先把它转换回std::string*,然后通过标准接口操作它的缓冲区,同时确保长度和内容匹配:void strRet(void* data) { std::string* str_ptr = static_cast<std::string*>(data); // 先确保string有足够的容量存放1500个字符 str_ptr->resize(1500); // resize会直接设置size,并确保缓冲区足够 char* buf = str_ptr->data(); // 获取可写的缓冲区指针 // 现在可以往buf里写1500个字符,注意不要越界 memset(buf, 'x', 1500); // 因为resize已经把size设为1500了,所以此时size()和strlen(c_str())会一致 }检查并修复越界写入的问题
如果你之前是直接往std::string的缓冲区里写超过它当前容量的内容,那会直接破坏内存(比如覆盖了string的内部成员)。这种情况下,一定要先调用reserve()(预留容量,不改变size)或者resize()(改变size并预留容量)来确保缓冲区足够大,再进行写入操作。绝对禁止直接修改
std::string的内部成员
不要试图通过强制类型转换去直接修改std::string的内部长度变量或者缓冲区指针,这是标准明确禁止的未定义行为,会导致各种诡异的问题。
内容的提问来源于stack exchange,提问作者Vishal Sharma

