2

My strtol function fails to set errno during overflown conversion.

#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <getopt.h>
#include <errno.h>
#include <stdlib.h>    

int main(int argc, char **argv) {

    errno = 0;
    int e = strtol("1000000000000000", NULL, 10);
    printf("%d %d\n", errno, e);

    return 0;
}

returns

0 -1530494976

What do I do wrong?

Compiler

gcc (Ubuntu 4.9.2-10ubuntu13) 4.9.2

Options

gcc -Wall -std=gnu99 -O2
Krzysztofik
  • 391
  • 3
  • 9

2 Answers2

5

There is nothing wrong with the implementation of strtol() but there is with your code.

The return type of this function is long (see the trailing l) and apparently the value 1000000000000000 can be represented by the long integer type. However the return value is assigned to e whose type is int which is unable to represent this value. What then happens is implementation-defined.

So change int e to long e and "%d %d\n" to "%d %ld\n". If you want to keep it as int, then you have to check if the value is outside of its range of representable values by yourself:

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <limits.h>  // for INT_{MIN,MAX}
int
main(void)
{
    errno = 0;
    long f = strtol("1000000000000000", NULL, 10);
    if (errno == ERANGE) {
        puts("value not representable by long (or int)");
    } else if (f < INT_MIN || f > INT_MAX) {
        puts("value not representable by int");
    } else {
        int e = f;
        printf("%d\n", e);
    }
}
cremno
  • 4,672
  • 1
  • 16
  • 27
-1

It seems like both Microsoft [1] and Apple [2] implementations have the setting of errno commented out.

[1] http://research.microsoft.com/en-us/um/redmond/projects/invisible/src/crt/strtol.c.htm

[2] http://www.opensource.apple.com/source/xnu/xnu-1456.1.26/bsd/libkern/strtol.c

Philip
  • 271
  • 1
  • 15