scanf修改其他变量是BUG吗?GCC下给main加void参数为何可解决?
问题根因
这不是GCC的BUG,本质是你使用的mingw-w64默认链接的**微软旧版C运行时库(msvcrt.dll)**不支持C99标准新增的%hhd格式符导致的未定义行为:
- 旧版msvcrt.dll识别不了
%hhd,会把它当成%d处理,%d对应需要写入4字节的int类型空间 - 你给
scanf传的是char类型的指针,只有1字节的合法写入空间,scanf写4字节直接造成栈溢出,覆盖了栈上相邻的condition变量的内存内容 - 每次执行
scanf都会把condition的值冲成0,所以你每次condition++之后输出永远是1,循环永远不会退出
其他现象解释
- 为什么注释
scanf就正常?
没有了栈溢出操作,condition变量的自增逻辑不受干扰,自然按预期运行。 - 为什么Clang下运行正常?
Clang的Windows版本通常默认使用适配C99标准的运行时库,能正确识别%hhd格式符,只会写入1字节到char空间,不会发生栈溢出。 - 为什么给main加
void参数问题就消失?
函数签名修改后,编译器会调整栈帧的内存布局、变量对齐规则,此时scanf溢出写入的4字节刚好没有覆盖到condition变量所在的内存,所以看起来问题消失了,但本质还是存在未定义行为,属于巧合的正常,不是真正修复了问题。
修复方案
可以任选以下一种方式彻底解决问题:
- 把
char choice改成int choice,配合%d格式符使用,避免短整型的格式兼容问题 - 如果一定要用
char类型存储,编译的时候给gcc加上-D__USE_MINGW_ANSI_STDIO=1参数,强制mingw使用自己实现的符合C99标准的格式化输入输出逻辑,就可以正确识别%hhd - 升级你的mingw-w64版本,新版本默认已经开启C99格式化支持,不会出现这个问题
内容的提问来源于stack exchange,提问作者Kaiyakha
相关产品推荐
相关产品推荐

