Wednesday, October 5, 2022

[SOLVED] compare between two size_t always return true when first of them is recived using %d

Issue

Following code will due to infinite loop. I know that using %d format instead of %zu for getting a size_t from input on scanf function is wrong. But why condition is TRUE ?? How ?

  size_t c;
  scanf("%d", &c);
 
  for (size_t i = 0; i < c; i++)
    printf("%d\n", i);

If I change i type to int, problem will solved. But why ?

Other examples :

  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);

Out

$ ./a.out
100
TRUE
c: 0x7f6400000064
b: 0xa

How can I understand this problem and mechanism ? please help me to searching ...

Compiler details:

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) 

OS:

archlinux
Linux developer 5.18.6-arch1-1 #1 SMP PREEMPT_DYNAMIC Wed, 22 Jun 2022 18:10:56 +0000 x86_64 GNU/Linux

Solution

The behavior on using %d to read a size_t item is undefined - neither the compiler nor the runtime environment are required to handle the situation in any particular way. The result can quite literally be anything - your code could crash outright, you could get garbled input or output, or your code could work as expected, and each of those outcomes would be considered equally "correct" as far as the language is concerned.

Most likely the problem is that size_t is larger than an int, so reading an input with %d only affects the lower sizeof (int) bytes, but the upper bytes are unaffected. Since you don't initialize c, it contains some indeterminate, most likely non-zero value. If c is 8 bytes wide and had an initial value of 0xFFFFFFFFFFFFFFFF, then after a scanf with %d and an input of 100, it would (likely) have a value of 0xFFFFFFFF00000064.

scanf doesn't know that c is a size_t - it only knows that you told it to read an int value into the first sizeof (int) bytes of the first argument.

Use the right conversion specifiers for both input and output, always. Use %zu for reading and writing size_t values, use %d for int values, use %p for pointer values, etc.



Answered By - John Bode
Answer Checked By - Cary Denson (WPSolving Admin)