sscanf解析%%不符合C17标准预期,疑为特定平台编译器Bug?
MinGW-W64平台sscanf行为不符合C17标准预期的问题分析
问题背景
这是C17标准第238页的示例程序:
#include <stdio.h> // C17标准第238页示例5 int main(void) { int n = 0; int i = 0; n = sscanf("foo %bar 42", "foo%%bar%d", &i); printf("n = %d\ni = %d\n", n, i); return 0; }
根据C17标准,该程序的预期输出为:
n = 1 i = 42
不同平台测试结果
MinGW-W64 x86_64-ucrt-posix-seh(gcc 12.1.0)
实际运行输出与标准预期不符:
n = 0 i = 0
该平台gcc配置信息:
Using built-in specs. COLLECT_GCC=D:\mingw64\bin\gcc.exe COLLECT_LTO_WRAPPER=d:/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/12.1.0/lto-wrapper.exe OFFLOAD_TARGET_NAMES=nvptx-none Target: x86_64-w64-mingw32 Configured with: ../configure --prefix=/R/winlibs64-11.3.0ucrt/inst_gcc-12.1.0/share/gcc --build=x86_64-w64-mingw32 --host=x86_64-w64-mingw32 --enable-offload-targets=nvptx-none --with-pkgversion='MinGW-W64 x86_64-ucrt-posix-seh, built by Brecht Sanders' --with-tune=generic --enable-checking=release --enable-threads=posix --disable-sjlj-exceptions --disable-libunwind-exceptions --disable-serial-configure --disable-bootstrap --enable-host-shared --enable-plugin --disable-default-ssp --disable-rpath --disable-libstdcxx-debug --disable-version-specific-runtime-libs --with-stabs --disable-symvers --enable-languages=c,c++,fortran,lto,objc,obj-c++,jit --disable-gold --disable-nls --disable-stage1-checking --disable-win32-registry --disable-multilib --enable-ld --enable-libquadmath --enable-libada --enable-libssp --enable-libstdcxx --enable-lto --enable-fully-dynamic-string --enable-libgomp --enable-graphite --enable-mingw-wildcard --enable-libstdcxx-time --disable-libstdcxx-pch --with-mpc=/e/Prog/winlibs64-11.3.0ucrt/custombuilt --with-mpfr=/e/Prog/winlibs64-11.3.0ucrt/custombuilt --with-gmp=/e/Prog/winlibs64-11.3.0ucrt/custombuilt --with-isl=/e/Prog/winlibs64-11.3.0ucrt/custombuilt --enable-libstdcxx-backtrace --enable-install-libiberty --enable-__cxa_atexit --without-included-gettext --with-diagnostics-color=auto --enable-clocale=generic --with-libiconv --with-system-zlib --with-build-sysroot=/R/winlibs64-11.3.0ucrt/gcc-12.1.0/build_mingw/mingw-w64 CFLAGS='-I/e/Prog/winlibs64-11.3.0ucrt/custombuilt/include/libdl-win32 -D__USE_MINGW_ACCESS' CXXFLAGS=-D__USE_MINGW_ACCESS LDFLAGS='-Wl,--disable-nxcompat -Wl,--disable-high-entropy-va -Wl,--disable-dynamicbase' Thread model: posix Supported LTO compression algorithms: zlib zstd gcc version 12.1.0 (MinGW-W64 x86_64-ucrt-posix-seh, built by Brecht Sanders)
Ubuntu平台(gcc 11.4.0)
实际运行输出符合标准预期:
n = 1 i = 42
该平台gcc配置信息:
Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/11/lto-wrapper OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa OFFLOAD_TARGET_DEFAULT=1 Target: x86_64-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Ubuntu 11.4.0-1ubuntu1~22.04' --with-bugurl=file:///usr/share/doc/gcc-11/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-11 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none:amdgcn-amdhsa --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --with-build-config=bootstrap-lto-lean --enable-link-serialization=2 Thread model: posix Supported LTO compression algorithms: zlib zstd gcc version 11.4.0 (Ubuntu 11.4.0-1ubuntu1~22.04)
问题根源
这并非GCC编译器本身的Bug,而是MinGW-W64平台使用的**UCRT(通用C运行时库)**中sscanf实现的兼容性问题。
MinGW-W64在UCRT模式下,直接调用Windows系统提供的UCRT库函数,而非GCC自带的glibc。UCRT的sscanf在处理格式字符串中的%%bar匹配输入中的%bar时,未严格遵循C17标准:标准要求%%匹配输入中的单个%,后续的bar需严格匹配输入中的对应字符序列,但UCRT的实现此处存在逻辑偏差,导致匹配失败,最终sscanf返回0,未读取到任何有效数据。
而Ubuntu平台使用的glibc,其sscanf实现严格遵循C17标准,因此能得到预期结果。
解决建议
- 切换到MinGW-W64的MSVCRT模式(而非UCRT),测试是否能得到符合标准的输出;
- 向Windows UCRT开发团队提交该兼容性问题报告;
- 手动编写字符串匹配逻辑,绕过UCRT的这一行为缺陷。
内容的提问来源于stack exchange,提问作者hengxin
相关产品推荐
相关产品推荐

