Cosmin Cosmin - 1 month ago 20
C Question

C glitch, might be compiler? Solved

So I have this piece of code that runs just well on some compilers but on my uni linux machine it has an interesting bug. It is a simple code and I've done more complicated ones, but the fact is that if I input -10 and -8, it enters an if it should not, where it checks if the product is lower or equal to 0(in the product function)
As I said, if I run it on my personal laptop with a newer gcc(the machine's one is gcc version 4.4.7 20120313 (Red Hat 4.4.7-17) (GCC) , might that be an issue, can't think of anything else), it outputs just fine. Asked one of my cs lecturers and he can't think of a reason either

#include <stdio.h>

long int p(long int b, long int e)
{
long int i;
long int prod;
prod = b * e;

if(prod <= 0)
return 0;
prod = 1;
for(i=b ; i<=e ; ++i)
prod*=i;
return prod;
}

int main(void)
{
long int b, e;

scanf("%li %li", &b, &e);

printf("The product from range %li to %li is %i \n", b, e, p(b,e));

return 0;
}

Answer

The problem is that on an 64-bit build, using %i to read a long int, or to print one, leads to undefined behaviour. The correct format is %li. (On a 32-bit build, you can often 'get away' with the format mismatch, and IIRC, older versions of GCC did not even warn you about it — but GCC 6.2.0 does warn about the mismatch. Whether the compiler warns or not, it is still a problem.)

For example, this code:

#include <stdio.h>

static
long int p(long int b, long int e)
{
    long int i;
    long int prod;
    prod = b * e;

    printf("b = %ld; e = %ld; prod = %ld\n", b, e, prod);

    if (prod <= 0)
        return 0;
    prod = 1;
    for (i = b; i <= e; ++i)
        prod *= i;

    printf("prod = %ld\n", prod);
    return prod;
}

int main(void)
{
    long int b, e;

    if (scanf("%li %li", &b, &e) == 2)
    {
        printf("b = %ld; e = %ld\n", b, e);
        printf("The product from range %li to %li is %li \n", b, e, p(b, e));
    }

    return 0;
}

Can be run and produces:

$ ./pd83 <<< '-10 -8'
b = -10; e = -8
b = -10; e = -8; prod = 80
prod = -720
The product from range -10 to -8 is -720 
$

The <<< '-10 -8' is Bash speak to enter the two numbers on the program's standard input. Note the printing in lots of places with the correct format specifier. Your code wouldn't compile with my default compiler options — in part because of the format mismatches (output shown for a copy of your code in pd73.c):

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -c pd73.c
pd73.c:3:10: error: no previous prototype for ‘p’ [-Werror=missing-prototypes]
 long int p(long int b, long int e)
          ^
pd73.c: In function ‘main’:
pd73.c:21:11: error: format ‘%i’ expects argument of type ‘int *’, but argument 2 has type ‘long int *’ [-Werror=format=]
   scanf("%i %i", &b, &e);
           ^
pd73.c:21:14: error: format ‘%i’ expects argument of type ‘int *’, but argument 3 has type ‘long int *’ [-Werror=format=]
   scanf("%i %i", &b, &e);
              ^
pd73.c:23:35: error: format ‘%i’ expects argument of type ‘int’, but argument 2 has type ‘long int’ [-Werror=format=]
   printf("The product from range %i to %i is %i \n", b, e, p(b,e));
                                   ^
pd73.c:23:41: error: format ‘%i’ expects argument of type ‘int’, but argument 3 has type ‘long int’ [-Werror=format=]
   printf("The product from range %i to %i is %i \n", b, e, p(b,e));
                                         ^
pd73.c:23:47: error: format ‘%i’ expects argument of type ‘int’, but argument 4 has type ‘long int’ [-Werror=format=]
   printf("The product from range %i to %i is %i \n", b, e, p(b,e));
                                               ^
cc1: all warnings being treated as errors
$

The first warning is semi-acceptable; I'd not complain about it though code I write wouldn't generate it. The static is one way to remove it. Since no other source file needs the function, it can be made static. It means the optimizer can optimize more, too. The alternative is to include a prototype declaration for the function before it is defined. As the error message says, that's due to the -Wmissing-prototypes warning flag.

The other warnings are all serious problems.

Comments