[英]Type aware string to number conversion in C++
假設這個世界上的所有數字都是正整數,並且可以用uintX_t C ++類型表示。
讓我們考慮下一個很棒的代碼,將std :: string轉換為數字:
#include <string>
#include <cstdint>
#include <iostream>
template <typename T>
T MyAwsomeConversionFunction(const std::string& value)
{
T result = 0;
for(auto it = value.begin(); it != value.end() && std::isdigit(*it); ++it)
{
result = result * 10 + *it - '0';
}
return result;
}
int main(int argc, const char * argv[])
{
std::cout<<MyAwsomeConversionFunction<uint16_t>("1234")<<std::endl;
std::cout<<MyAwsomeConversionFunction<uint16_t>("123456")<<std::endl;
return 0;
}
如您所見,此函數存在多個錯誤,但我對特定函數感興趣:如何檢測何時我的類型不足以包含該值(例如第二次轉換調用),並在使result = result * 10 + *it - '0';
時避免使用UB result = result * 10 + *it - '0';
。 我想知道該操作是否會超過T
最大值。 這可能嗎?
編輯:請檢查是否有符號整數溢出在C ++中仍然是未定義的行為? 有關UB有關C ++中算術運算的更多信息。 我想避免執行result = result * 10 + *it - '0';
結果將何時溢出。 在答案中,該行仍在執行...
EDIT2:我在這里找到了答案: 如何檢測整數溢出?
編輯3:接受的答案適用於帶符號的類型。 對於無符號類型,干杯和hth。 -Alf的答案是正確的。
盡管可能會因錯誤而被我分開,但我會對此大吃一驚。 這不會處理字符串中的負值(您的原始代碼也不會)。 正如Alf在評論中提到的那樣,它僅限於ASCII數字。
template <typename T>
T MyAwsomeConversionFunction(const std::string& value)
{
T maxBeforeMult = std::numeric_limits<T>::max / 10;
T result = 0;
for(auto it = value.begin(); it != value.end() && std::isdigit(*it); ++it)
{
// Check if multiplying would overflow
if (result > maxBeforeMult)
{
// throw overflow
}
result = result * 10;
T digit = *it - 0;
// Check if adding would overflow
if (std::numeric_limits<T>::max - result < digit)
{
// throw overflow
}
result += digit;
}
return result;
}
您只需要向后工作,詢問給定的數字是否會溢出:
// When result exceeds this thresh, appending a digit will always overflow.
static const T thresh = std::numeric_limits<T>::max() / 10;
// When result equals this thresh, appending a digit larger than
// thresh_last_digit will overflow.
static const T thresh_last_digit = std::numeric_limits<T>::max() - 10 * thresh;
for(auto it = value.begin(); it != value.end() && std::isdigit(*it); ++it)
{
if(result > threshold)
throw std::overflow_error(value);
T digit = *it - '0';
if(result == threshold && digit > thresh_last_digit)
throw std::overflow_error(value);
result = result * 10 + digit;
}
對於無符號T
您可以隨時執行
T const original = result;
result = result * 10 + *it - '0';
if( result / 10 != original ) { throw 666; }
除非,用一些東西代替throw 666
。
有關使用溢出檢測將字符串→整數轉換的顯而易見的原始問題,請參見strtol
和family。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.