WSL(Ubuntu20.04)下调用C标准库strcpy、strtol结果异常问题
问题产生原因
核心问题是重叠内存调用strcpy触发了未定义行为,具体执行流程拆解如下:
- 初始状态
buf内容为a678b\0,第一次进入循环调用strtol(buf, &endptr, 10):- 首字符
a不是十进制数字,strtol返回0,endptr直接指向buf的首地址(也就是a所在的位置)
- 首字符
- 进入
x==0的分支,执行strcpy(buf, endptr + 1):- 此时
endptr + 1等于buf + 1,即strcpy的源地址和目标地址是同一块内存的重叠区域 - C标准明确规定
strcpy不支持重叠内存拷贝,重叠场景下的执行结果是未定义的。你使用的WSL环境下glibc的strcpy有面向多字节的优化逻辑,不会按逐字节顺序拷贝,导致拷贝过程中源字符串的未读取内容被提前覆盖,最终得到错误的buf内容,累加后得到错误结果68。
- 此时
修改后代码正常的原因
你新增了独立的中间缓冲区kk,先把endptr + 1指向的内容拷贝到和buf完全不重叠的kk中,再从kk拷贝到buf,两次strcpy的源、目标都不存在重叠,因此执行行为完全符合预期,最终累加得到正确结果678。
更简洁的修复方案
不需要额外的中间缓冲区,直接使用支持重叠内存拷贝的memmove函数即可:
if (x == 0) { memmove(buf, endptr + 1, strlen(endptr + 1) + 1); }
memmove会先判断内存重叠方向,选择合适的拷贝顺序,保证内容拷贝正确。
内容的提问来源于stack exchange,提问作者DerekWangTW
相关产品推荐
相关产品推荐

