gcc 当使用%d接收到两个size_t中第一个时,两个size_t之间的比较始终返回true

a9wyjsp7  于 2022-11-13  发布在  其他
关注(0)|答案(2)|浏览(180)

下面的代码将导致无限循环。我知道使用%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
puruo6ea

puruo6ea1#

使用%d读取size_t项的行为是 undefined -编译器和运行时环境都不需要以任何特定的方式来处理这种情况。结果可以是任何事情-你的代码可能会彻底崩溃,你可能会得到乱码的输入或输出,或者你的代码可以按预期的方式工作。并且就语言而言,这些结果中的每一个都将被认为是同样“正确的”。

  • 最有可能 * 的问题是size_tint大,所以用%d阅读一个输入只影响sizeof (int)的低位字节,而高位字节不受影响。如果c是8字节宽并且具有0xFFFFFFFFFFFFFFFF的初始值,则在具有%dscanf100的输入之后,它将(很可能)具有值0xFFFFFFFF00000064

scanf并不知道csize_t-它只知道你告诉它把一个int值读入第一个参数的第一个sizeof (int)字节。
在输入和输出时都要使用正确的转换说明符。使用%zu来读取和写入size_t值,使用%d来读取和写入int值,使用%p来读取和写入指针值,等等。

cqoc49vn

cqoc49vn2#

您的程式码有未定义的行为,因为%d需要指向int的指标,而不是指向size_t的指标,后者在内存中有不同的表示:

  • 在大多数64位系统中,size_t有64位,而int只有32位,因此size_t c; scanf("%d", &c);最多只修改c的存储值的一半,即小端序系统中的低位字。由于c未初始化,高位字可以具有任何值,其中大多数值将使其大于b

上面的解释是试探性的,该行为未定义,因此可能会发生其他情况。使用%zu读取和转换size_t类型的值,并启用所有警告(gcc -Wall -Wextraclang -Weverything)以让编译器检测此类错误:

#include <stdio.h>

int main() {
    size_t c;
    size_t b = 10;

    if (scanf("%zu", &c) == 1) {
        printf("%s\n", b < c ? "TRUE" : "FALSE");
        printf("c: 0x%zx\n", c);
        printf("b: 0x%zx\n", b);
    }
    return 0;
}

相关问题