Нужно ли приводить результат strtol к int? - PullRequest
4 голосов
/ 11 марта 2010

Следующий код не выдает предупреждение с g ++ 4.1.1 и -Wall.

int octalStrToInt(const std::string& s)
{    
    return strtol(s.c_str(), 0, 8);
}

Я ожидал предупреждения, потому что strtol возвращает long int, но моя функция возвращает только простое int. Могут ли другие компиляторы выдавать предупреждение здесь? Должен ли я привести приведенное значение к int в этом случае, как хорошая практика?

Ответы [ 5 ]

3 голосов
/ 11 марта 2010

Лучший подход:

long x = strtol(...); assert(x <= INT_MAX); return (int)x;

Вам нужно limits.h и assert.h

2 голосов
/ 11 марта 2010

Если у вас нет доступа к boost::numeric_cast, вы можете написать простую имитацию:

template <typename T, typename S>
T range_check(const S &s) {
    assert(s <= std::numeric_limits<T>::max());
    assert(s >= std::numeric_limits<T>::min());
    return static_cast<T>(s); // explicit conversion, no warnings.
}

return range_check<int>(strtol(some_value,0,8));

На самом деле это немного обманывает, поскольку он не работает для типов назначения с плавающей запятой. min() для них не такая же оценка, как для целочисленных типов, вам нужно проверить +/- max(). Упражнение для читателя.

Используете ли вы assert или какую-либо другую обработку ошибок, зависит от того, что вы на самом деле хотите сделать с неверным вводом.

Есть также boost::lexical_cast (от руки я не знаю, как сделать это восьмеричным) и stringstream. Прочитайте нужный вам тип, а не тип, в котором есть функция библиотеки C.

1 голос
/ 11 марта 2010

Вы не видите здесь никакого предупреждения, потому что типы данных "int" и "long int" на вашей платформе имеют одинаковый размер и диапазон. В зависимости от архитектуры они могут стать разными.

Чтобы защитить себя от странных ошибок, используйте проверку диапазона. Я предлагаю вам использовать std :: numeric_limits :: min / max (см.).

После проверки диапазона вы можете безопасно использовать static_cast или c-style cast.

С другой стороны, вы можете полагаться на ту же функциональность, реализованную в классе std :: stringstream. Преобразование с помощью std :: stringstream будет безопасным для платформы и безопасным для типов по умолчанию.

1 голос
/ 11 марта 2010

Вам может понадобиться флаг -Wconversion, чтобы включить эти предупреждения. Однако он не будет предупреждать о long -> int , так как они имеют одинаковый размер с GCC (значение не изменится из-за преобразования). Но это было бы, если вы конвертируете, например, long -> short

Полагаю, простое приведение не рекомендовано, поскольку это просто скрывало бы ошибки. Все будет в порядке после того, как вы проверите, что такое приведение не изменит значение, чтобы успокоить компилятор.

0 голосов
/ 11 марта 2010

Большинство современных компиляторов будут предупреждать о преобразовании и возможном усечении в зависимости от настроенного вами уровня предупреждения. На MSVC это уровень предупреждения 4.

Рекомендуется возвращать long из вашей функции, и позволить вызывающему коду решить, как обрабатывать преобразование. За исключением этого, по крайней мере, убедитесь, что значение, возвращаемое вами из strtol, поместится в int, прежде чем вы вернетесь, как предполагает Let_Me_Be.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...