Logical Puzzle

I’ve got a rather large collection of code, that compiles and runs as expected using gcc. In an attempt to optimize I am trying to compile this same code with pgcc. My initial attempts have not been met with success. I ran into a strange behavior and was able to isolate it into a simple program.

#include <stdio.h>

int testA(int v);
int testB(int v);

int main(int argc, char *argv[])
{
        printf("0 or  0: ");
        if ( testA(0) | testB(0) )
                printf("TRUE\n");
        else
                printf("FALSE\n");

        printf("0 or  1: ");
        if ( testA(0) | testB(1) )
                printf("TRUE\n");
        else
                printf("FALSE\n");

        printf("1 or  0: ");
        if ( testA(1) | testB(0) )
                printf("TRUE\n");
        else
                printf("FALSE\n");

        printf("1 or  1: ");
        if ( testA(1) | testB(1) )
                printf("TRUE\n");
        else
                printf("FALSE\n");

        printf("0 and 0: ");
        if ( testA(0) & testB(0) )
                printf("TRUE\n");
        else
                printf("FALSE\n");

        printf("0 and 1: ");
        if ( testA(0) & testB(1) )
                printf("TRUE\n");
        else
                printf("FALSE\n");

        printf("1 and 0: ");
        if ( testA(1) & testB(0) )
                printf("TRUE\n");
        else
                printf("FALSE\n");

        printf("1 and 1: ");
        if ( testA(1) & testB(1) )
                printf("TRUE\n");
        else
                printf("FALSE\n");

        return 1;
}

int testA(int v)
{
        printf("Test A = %d -> ",v);
        return v;
}

int testB(int v)
{
        printf("Test B = %d -> ",v);
        return v;
}

Now if I compile this little program with gcc and run it I get the following output:

  • 0 or 0: Test A = 0 -> Test B = 0 -> FALSE
    0 or 1: Test A = 0 -> Test B = 1 -> TRUE
    1 or 0: Test A = 1 -> Test B = 0 -> TRUE
    1 or 1: Test A = 1 -> Test B = 1 -> TRUE
    0 and 0: Test A = 0 -> Test B = 0 -> FALSE
    0 and 1: Test A = 0 -> Test B = 1 -> FALSE
    1 and 0: Test A = 1 -> Test B = 0 -> FALSE
    1 and 1: Test A = 1 -> Test B = 1 -> TRUE

If I compile this little program with pgcc and run it I get the following output:

  • 0 or 0: Test B = 0 -> Test A = 0 -> FALSE
    0 or 1: Test B = 1 -> Test A = 0 -> TRUE
    1 or 0: Test B = 0 -> Test A = 1 -> TRUE
    1 or 1: Test B = 1 -> Test A = 1 -> TRUE
    0 and 0: Test B = 0 -> Test A = 0 -> FALSE
    0 and 1: Test B = 1 -> Test A = 0 -> FALSE
    1 and 0: Test B = 0 -> Test A = 1 -> FALSE
    1 and 1: Test B = 1 -> Test A = 1 -> TRUE

Here’s where I expose my ignorance. I was expecting something along the lines of:

  • 0 or 0: Test A = 0 -> Test B = 0 -> FALSE
    0 or 1: Test A = 0 -> Test B = 1 -> TRUE
    1 or 0: Test A = 1 -> TRUE
    1 or 1: Test A = 1 -> TRUE
    0 and 0: Test A = 0 -> FALSE
    0 and 1: Test A = 0 -> FALSE
    1 and 0: Test A = 1 -> Test B = 0 -> FALSE
    1 and 1: Test A = 1 -> Test B = 1 -> TRUE

That is, I expected that the test would stop as soon as it encountered a “true” statement in the OR tests, and that it would stop as soon as it encountered a “false” statement in the AND tests. I suppose when the test statements include function they must all be evaluated first and then tested?

The more important puzzle is that when compiled with pgcc, the statements were actually evaluated in reverse order. Where as when compiled with gcc the statements were evaluated in the order I had expected. Can anyone explain to me why this should be so?

Hi Emma,

You’re using the bit-wise operators ("|", “&”) when you should be using the logical operators ("||", “&&”). It works as expected if you use the logicals.

grandcanyon:/tmp% cat test.c
#include <stdio.h>

int testA(int v);
int testB(int v);

int main(int argc, char *argv[])
{
        printf("0 or  0: ");
        if ( testA(0) || testB(0) )
                printf("TRUE\n");
        else
                printf("FALSE\n");

        printf("0 or  1: ");
        if ( testA(0) || testB(1) )
                printf("TRUE\n");
        else
                printf("FALSE\n");

        printf("1 or  0: ");
        if ( testA(1) || testB(0) )
                printf("TRUE\n");
        else
                printf("FALSE\n");

        printf("1 or  1: ");
        if ( testA(1) || testB(1) )
                printf("TRUE\n");
        else
                printf("FALSE\n");

        printf("0 and 0: ");
        if ( testA(0) && testB(0) )
                printf("TRUE\n");
        else
                printf("FALSE\n");

        printf("0 and 1: ");
        if ( testA(0) && testB(1) )
                printf("TRUE\n");
        else
                printf("FALSE\n");

        printf("1 and 0: ");
        if ( testA(1) && testB(0) )
                printf("TRUE\n");
        else
                printf("FALSE\n");

        printf("1 and 1: ");
        if ( testA(1) && testB(1) )
                printf("TRUE\n");
        else
                printf("FALSE\n");

        return 1;
}

int testA(int v)
{
        printf("Test A = %d -> ",v);
        return v;
}

int testB(int v)
{
        printf("Test B = %d -> ",v);
        return v;
}
grandcanyon:/tmp% pgcc test.c -o test_pgcc.out
grandcanyon:/tmp% gcc test.c -o test_gcc.out
grandcanyon:/tmp% test_pgcc.out
0 or  0: Test A = 0 -> Test B = 0 -> FALSE
0 or  1: Test A = 0 -> Test B = 1 -> TRUE
1 or  0: Test A = 1 -> TRUE
1 or  1: Test A = 1 -> TRUE
0 and 0: Test A = 0 -> FALSE
0 and 1: Test A = 0 -> FALSE
1 and 0: Test A = 1 -> Test B = 0 -> FALSE
1 and 1: Test A = 1 -> Test B = 1 -> TRUE
grandcanyon:/tmp% test_gcc.out
0 or  0: Test A = 0 -> Test B = 0 -> FALSE
0 or  1: Test A = 0 -> Test B = 1 -> TRUE
1 or  0: Test A = 1 -> TRUE
1 or  1: Test A = 1 -> TRUE
0 and 0: Test A = 0 -> FALSE
0 and 1: Test A = 0 -> FALSE
1 and 0: Test A = 1 -> Test B = 0 -> FALSE
1 and 1: Test A = 1 -> Test B = 1 -> TRUE
grandcanyon:/tmp%



The more important puzzle is that when compiled with pgcc, the statements were actually evaluated in reverse order. Where as when compiled with gcc the statements were evaluated in the order I had expected. Can anyone explain to me why this should be so?

The order of bitwise operations are compiler dependent. The order of logical operations are always evaluated from left to right.

Hope this helps,
Mat

Huh, I just figured that out for myself. I was hoping to get rid of the post before my stupidity was revealed. Thank-you! :D

Don’t worry about it, Emma. I’m sure if you asked 100 programmers if they have made this mistake, all 100 (including myself) would answer yes.

  • Mat