How can -1 be greater than 4?

Asked

Viewed 1,582 times

49

How this code can execute in this way?

#include <stdio.h>

int main(void) {
    printf("tamanho de um inteiro: %d\n", sizeof(int));
    if(sizeof(int) > -1) {
        printf("4 é maior que -1");
    } else {
        printf("-1 é maior que 4");
    }
    return 0;
}

Exit:

-1 é maior que 4

Intuitively -1 must be less than 4 always, why does this kind of "error" happen? The computer is not a machine that does not make mistakes?

2 answers

58


Even though my mother and some programmers think that the computer makes its own decisions, it’s only capable of doing what humans determine.

Of course, a computer can produce wrong results without a human making a mistake using it. But that means that a human designed the computer or at least some component of it wrong. Or the specification has determined that the error will be possible, and whoever uses that hardware needs to be aware of it and take the proper steps to make sure it doesn’t bring unwanted results. In practice errors occur more in the same software.

Programmers make a lot of mistakes, often because they don’t understand every aspect of what they’re doing. It’s normal. There is no one who knows everything, even if this is all about software development.

This specific "problem" occurs because of the difference in types used in the code. It is not very obvious but if you look in the specification you will see that the operator sizeof returns a type value unsigned int, more specifically a size_t and the comparison in if is being done with a signed int or simply int. I mean, you’re comparing one guy who has a signal to another who doesn’t. Therefore there is an implicit conversion of the signaled type to the unmarked type. In this conversion there is a change in the interpretation of the data.

Knowing that the return of the operator used is an integer without signal and that the cast implicit occurs and even if a negative value when converted to a type without signal starts counting the largest integer possible and reduces the more the negative - since it ignores the bit sign as a sign and consider it as part of the number - it is easy to understand what is occurring. And the problem is just a misinterpretation of a human. The computer did what they told it to do.

It’s easier to understand by printing the -1 without a signal:

#include <stdio.h>

int main(void) {
    printf("tamanho de um inteiro: %d\n", sizeof(int));
    printf("-1 com cast: %u\n", -1);
    if(sizeof(int) > -1) {
        printf("4 é maior que -1");
    } else {
        printf("-1 é maior que 4");
    }
    return 0;
}

So the message should be "4294967295 is greater than 4".

Behold working in the ideone. And in the repl it.. Also put on the Github for future reference.

Some people will take advantage of this to criticize the implied conversion. In fact it is bad when it is expected that the language will be used by programmers who do not understand well the whole functioning of what he is using or who usually has inattentions. But I think the more help that gets in the way.

In a way that brings me back to what I answered another question. The fact that you don’t know the type an expression results from is the real problem of the code. Making everything explicit would help avoid some problems but would make the code longer and redundant by adding unnecessary detail. Ironically this can be beneficial in languages that target programmers who don’t care about the details.

Completion

Learn the types of every sub-expression you’re computing. And make sure you’re using the right types. In this case if the intention really is to compare the size of the type with signed integer literal, then you must ensure that the result of sizeof(int) be a int through a cast. Thus:

#include <stdio.h>

int main(void) {
    printf("tamanho de um inteiro: %d\n", (int)sizeof(int));
    if((int)sizeof(int) > -1) printf("4 é maior que -1");
    else printf("-1 é maior que 4");
}

Behold working in the ideone. And in the repl it.. Also put on the Github for future reference.

This pair of question and answer was inspired by a reddit discussion that I found interesting to show.

  • 3

    Really interesting. Thanks for sharing!

34

In fact sizeof returns a size_t type, which should be unsigned. The problem occurs in the unsigned binary Signed to binary conversion, if the programmer is not careful. The conversion of a binary number to a negative decimal integer as -1, for example, is done in C by the complement of two of its positive equivalent.

Example of how the computer sees a negative number: Takes the number 1 -- positive -- in binary form with the size of 4 bytes (32 bits, or 32 binary digits):

00000000 00000000 00000000 00000001 -> binário de 1
11111111 11111111 11111111 11111110 -> complemento de um (inverte-se os bits)
                                + 1 -> complemento de dois (soma 1 ao complemento)
___________________________________
11111111 11111111 11111111 11111111 -> complemento de dois equivalendo a -1

The problem occurs when the computer treats a number that should be negative as positive. For example, the decimal number -1 above, treated as positive is recognized by the computer as 4294967295 decimal, which is obviously greater than the number 4 of its kind.

Taking this into account, one should be very careful of how the computer and the programming language deals with the implicit conversion of types. Study enough casting to make sure you always do it safely.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.