3

I saw it in a code like this

while(~scanf("%d",&a))

I know that scanf() has return value,but I can’t understand what does ~ mean

Barmar
  • 741,623
  • 53
  • 500
  • 612
Moon
  • 73
  • 1
  • 2
  • 8

2 Answers2

10

This is a silly trick that relies on EOF having all its bits set. Since the standard does not guarantee the exact value of EOF, the behavior of this program is platform-dependent.

When scanf detects end-of-input, it returns EOF. Standard requires EOF to be negative. Very often EOF is set to -1. When ~ is applied to -1, you get back a zero, so the loop stops. On platforms with EOF defined as some other negative number the loop will never stop. Code's behavior also depends on the implementation-defined behavior of ~ with signed values.

You should rewrite the loop as follows:

while (scanf("%d", &a) != EOF) {
    ...
}
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 3
    It also depends on implementation-dependent behavior of bitwise operators on signed values. – Barmar Jun 23 '18 at 02:57
  • 2
    It also depends on the input being correct. Add a non-numeric character to the input and you have an infinite loop. – rici Jun 23 '18 at 02:59
  • @rici We don't know what he does inside the loop, though - he may be taking non-numerics off the input buffer, so it's hard to say for sure. – Sergey Kalinichenko Jun 23 '18 at 03:01
  • 2
    So, to echo @rici's point, the loop condition should more likely be `while (scanf("%d", &a) == 1) { … }` so that it stops on error or EOF. It doesn't make the code in the question any more sensible, though. Without capturing the value returned by `scanf()` explicitly, the body of the `!= EOF` loop can't reliably detect whether a value was read or not: `while ((rc = scanf("%d", &a)) != EOF) { …code that checks rc before using a… }` would be OK. – Jonathan Leffler Jun 23 '18 at 03:01
  • 1
    @JonathanLeffler It's hard to say without seeing what he does inside the loop. I wanted to suggest `== 1` at the beginning, but that would not be equivalent to author's intended behavior (although I'd write `== 1` if it were my code :-) – Sergey Kalinichenko Jun 23 '18 at 03:03
  • @dasblinkenlight: we know they don't save the value returned by scanf, which implies that they don't know whether a non-numeric value was present. – rici Jun 23 '18 at 03:08
3

There are a few knowledge tidbits that are needed to explain how this works and what it does.

First: ~

~ is the bitwise NOT operator. It inverts the bits in a binary number.

ex:

1010111
0101000

Second: scanf()

If you look at the man pages for scanf():

NAME
   scanf,  fscanf, sscanf, vscanf, vsscanf, vfscanf 

   ...

RETURN VALUE
   These functions return the number of input items  successfully  matched
   and assigned, which can be fewer than provided for, or even zero in the
   event of an early matching failure.

   The value EOF is returned if the end of input is reached before  either
   the  first  successful conversion or a matching failure occurs.  EOF is
   also returned if a read error occurs, in which case the error indicator
   for  the  stream  (see ferror(3)) is set, and errno is set indicate the
   error.

We can see that when scanf() is successful, it will return some integer equal to or greater than 0. If it reached EOF or was otherwise unsuccessful, it will return the (integer) value EOF.

Third: the trick

If you NOT most non-zero integers, you will still receive a non-zero value in return. The exception to this would be a number than when represented in binary would be entirely 1's:

~11111111 = 00000000 = 0

As it turns out in most computer systems this happens to be the value -1 which just so happens to be the value typically assigned to EOF

So

while(~scanf("%d",&a))

Could be re-written as

while(scanf("%d",&a) != -1)

or

while(scanf("%d",&a) != EOF)
Community
  • 1
  • 1
Matt
  • 82
  • 3