Нужно ли приводить результат strtol к int?
Следующий код не выдает предупреждение с g++ 4.1.1 и -Wall
,
int octalStrToInt(const std::string& s)
{
return strtol(s.c_str(), 0, 8);
}
Я ожидал предупреждения, потому что strtol возвращает long int
но моя функция только возвращает простую int
, Могут ли другие компиляторы выдавать предупреждение здесь? Должен ли я привести приведенное значение к int в этом случае в качестве хорошей практики?
5 ответов
Вам может понадобиться флаг -Wconversion, чтобы включить эти предупреждения. Тем не менее, он не будет предупреждать о long -> int, поскольку они имеют одинаковый размер с GCC (значение не изменится из-за преобразования). Но это будет, если вы конвертируете, например, long -> short
Я полагаю, что просто не рекомендуется делать приведение типов, поскольку это просто скрывает вероятность ошибок. Все будет в порядке после того, как вы проверите, что такое приведение не изменит значение, чтобы успокоить компилятор.
Лучший подход это:
long x = strtol(...); assert(x <= INT_MAX); return (int)x;
Тебе нужно limits.h
а также assert.h
Если у вас нет доступа к 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 для него.
Здесь вы не увидите никаких предупреждений, потому что типы данных "int" и "long int" на вашей платформе имеют одинаковый размер и диапазон. В зависимости от архитектуры они могут стать разными.
Чтобы защитить себя от странных ошибок, используйте проверку диапазона. Я предлагаю вам использовать std::numeric_limits::min/max (см.).
После проверки диапазона вы можете безопасно использовать static_cast или c-style cast.
С другой стороны, вы можете положиться на ту же функциональность, реализованную в классе std:: stringstream. Преобразование с помощью std:: stringstream будет безопасным для платформы и безопасным для типов по умолчанию.
Большинство современных компиляторов будут предупреждать о преобразовании и возможном усечении в зависимости от настроенного вами уровня предупреждения. На MSVC это уровень предупреждения 4.
Рекомендуется возвращать long из вашей функции, и позволить вызывающему коду решить, как обработать преобразование. За исключением этого, по крайней мере, убедитесь, что значение, возвращаемое вами из strtol, поместится в int, прежде чем вы вернетесь, как предполагает Let_Me_Be.