簡體   English   中英

在C ++中將類型識別字符串轉換為數字

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM