下面的代码将导致无限循环。我知道使用%d
而不是%zu
来从scanf
函数的输入中获取size_t
是错误的。但是为什么条件是TRUE呢??怎么做?
size_t c;
scanf("%d", &c);
for (size_t i = 0; i < c; i++)
printf("%d\n", i);
如果我把i
类型改为int,问题就解决了。但是为什么呢?
其他示例:
size_t c;
size_t b = 10;
scanf("%d", &c);
printf("%s\n", b < c ? "TRUE" : "FALSE");
printf("c: %p\n", c);
printf("b: %p\n", b);
输出
$ ./a.out
100
TRUE
c: 0x7f6400000064
b: 0xa
我如何理解这个问题和机制?请帮助我搜索...
编译器详细信息:
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/12.1.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: /build/gcc/src/gcc/configure --enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++ --enable-bootstrap --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/ --with-linker-hash-style=gnu --with-system-zlib --enable-__cxa_atexit --enable-cet=auto --enable-checking=release --enable-clocale=gnu --enable-default-pie --enable-default-ssp --enable-gnu-indirect-function --enable-gnu-unique-object --enable-linker-build-id --enable-lto --enable-multilib --enable-plugin --enable-shared --enable-threads=posix --disable-libssp --disable-libstdcxx-pch --disable-werror --with-build-config=bootstrap-lto --enable-link-serialization=1
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 12.1.0 (GCC)
操作系统:
archlinux
Linux developer 5.18.6-arch1-1 #1 SMP PREEMPT_DYNAMIC Wed, 22 Jun 2022 18:10:56 +0000 x86_64 GNU/Linux
2条答案
按热度按时间puruo6ea1#
使用
%d
读取size_t
项的行为是 undefined -编译器和运行时环境都不需要以任何特定的方式来处理这种情况。结果可以是任何事情-你的代码可能会彻底崩溃,你可能会得到乱码的输入或输出,或者你的代码可以按预期的方式工作。并且就语言而言,这些结果中的每一个都将被认为是同样“正确的”。size_t
比int
大,所以用%d
阅读一个输入只影响sizeof (int)
的低位字节,而高位字节不受影响。如果c
是8字节宽并且具有0xFFFFFFFFFFFFFFFF
的初始值,则在具有%d
的scanf
和100
的输入之后,它将(很可能)具有值0xFFFFFFFF00000064
。scanf
并不知道c
是size_t
-它只知道你告诉它把一个int
值读入第一个参数的第一个sizeof (int)
字节。在输入和输出时都要使用正确的转换说明符。使用
%zu
来读取和写入size_t
值,使用%d
来读取和写入int
值,使用%p
来读取和写入指针值,等等。cqoc49vn2#
您的程式码有未定义的行为,因为
%d
需要指向int
的指标,而不是指向size_t
的指标,后者在内存中有不同的表示:size_t
有64位,而int
只有32位,因此size_t c; scanf("%d", &c);
最多只修改c
的存储值的一半,即小端序系统中的低位字。由于c
未初始化,高位字可以具有任何值,其中大多数值将使其大于b
。上面的解释是试探性的,该行为未定义,因此可能会发生其他情况。使用
%zu
读取和转换size_t
类型的值,并启用所有警告(gcc -Wall -Wextra
或clang -Weverything
)以让编译器检测此类错误: