2015-08-19 2 views
2

Моя функция strtol не может установить errno во время переполнения.Strtol не устанавливает errno при преобразовании переполнения

#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; 
} 

возвращает

0 -1530494976 

Что делать неправильно?

Компилятор

gcc (Ubuntu 4.9.2-10ubuntu13) 4.9.2 

Варианты

gcc -Wall -std=gnu99 -O2 
+2

Какой компилятор (и его версия) вы используете? Включили ли вы все необходимые заголовки? –

+0

Что говорит страница man - это тип возврата 'strol'? – kaylum

+0

Хорошо, компилятор и заголовки добавлены – Krzysztofik

ответ

5

Там нет ничего плохого в реализации strtol() но есть с вашим кодом.

Тип возврата этой функции long (см заднюю l) и, по-видимому значение 1000000000000000 может быть представлено типом long целого. Однако возвращаемое значение присваивается e, тип которого int, который не может представить это значение. Затем происходит реализация.

Поэтому измените int e на long e и "%d %d\n" на "%d %ld\n". Если вы хотите сохранить его как int, то вы должны проверить, если значение находится вне его диапазона представимых значений сами:

#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); 
    } 
} 
+0

Спасибо за ответ. Возможно, вы знаете, есть ли функция для нормального преобразования int, с обнаружением переполнения? – Krzysztofik

+0

@ Krzysztofik: Я добавил пример. – cremno

+0

@ cremno На самом деле, это был мозговой пердит. Вы правы, это LP64, а не LLP64. – Sneftel

-1

Похоже, как Microsoft [1] и Apple, [2] реализаций установка errno закомментирована.

[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

+0

Он использует GCC на Ubuntu. – Barmar

+1

'strtol' не может обнаружить принуждение' int', которое происходит за пределами 'strtol' – fukanchik

+1

Это также не исходный код Visual C++ CRT, а ссылка Apple выглядит как ядро, а не код libc. – cremno

0

Вы делаете хорошо, но вы не проверить значение errno для strtol но для printf() .... Не понимаю, позвольте мне объяснить ... После long f = strtol("1000000000000000", NULL, 10); заявление вы должны сначала сохранить значение errno. Потому что после этого заявления вы будете называть printf() заявление, которое также устанавливает errno соответственно.

printf("errno is: %d\n", errno); 

Так что в этом заявлении «ERRNO» дает индикацию ошибки для printf() не для strtol() ... Для того, чтобы сделать так, сохранить «ERRNO» перед вызовом любой функции библиотеки, потому что большинство функций библиотеки взаимодействуют с «ERRNO». Правильное использование:

long f = strtol("1000000000000000", NULL, 10); 
int saved_error = errno;  // Saving the error... 
printf("errno is: %d\n", saved_error); 

Теперь проверьте его. Разумеется, это даст правильный результат ... И еще одна вещь, чтобы преобразовать этот errno в какую-нибудь значимую строку для представления ошибки. Используйте strerror() функцию:

printf("Error is: %s\n", strerror(saved_error)); 

Cremno's answer является правильным, но это более общий характер.

Смежные вопросы