Сравнение на променлива size_t с -1 (максимална стойност на размера) в C++ код

Преработвам библиотека и се опитвам да се отърва от много gcc предупреждения. Голямата част от тези предупреждения са за сравнение със знак/без знак и са свързани с използването на size_t. Библиотеката работи на 64 битови Linux системи.

Един програмист използва -1 като специална стойност, подобна на std::string::npos. Има много места в библиотеката, където кодът изглежда така:

class AnnotationBase
{
    public:
        size_t m_offset = -1;
        size_t m_length = -1;

}

...

AnnotationBase foo(const std::string& text, const AnnotationBase& annot)
{
    AnnotationBase newAnnot;

    // do some job with annotations and text
    ...

    if(newAnnot.m_offset == -1)
    {
        // do some other job
        ...
    }

    return newAnnot;
}

Проблемът се крие в предупреждението, което gcc генерира на ред if(newAnnot.m_offset == -1) поради сравнение със знак/без знак:

"warning: comparison between signed and unsigned integer expressions [-Wsign-compare]"

Какъв е правилният начин за сравняване на променлива size_t в C++ с максималната стойност (-1) без предупреждение? Правенето на това като if(newAnnot.m_offset == std::numeric_limits<size_t>::max()) е много неудобно поради сложността и дължината на този израз.

Добър начин ли е да се използва дефинирана стойност в стил C SIZE_MAX или е по-добре да се създаде собствена константа като namesapce libling { const NONE = std::numeric_limits<size_t>::max(); } (Създаването на нова константа води до много подобни константи в различни библиотеки и пространства от имена като libling::NONE, libother::UNKNOWN, liblongnamesapcename::NOTHING)?


person Chen Gupta    schedule 02.08.2014    source източник
comment
Със сигурност бих използвал именувана константа, напр. if (newAnnot.m_offset == NoneOffset) ... , което след това може да бъде декларирано като const size_t NoneOffset = -1;, което трябва да реши проблема. Използването на вашата дефиниция на NONE също би свършило работа.   -  person Mats Petersson    schedule 02.08.2014


Отговори (4)


Можете да направите това, което прави std::string и да дефинирате static const size_t AnnotationBase::npos = -1. След това използвайте това в сравненията като конвенция. Не бих счел една константа на библиотека за проблем, но ако искате да избегнете това, можете да използвате std::string::npos директно (това обаче прави кода по-твърд).

person eerorika    schedule 02.08.2014

или можете да използвате тази единична заглавка библиотека и да пишете

if(sweet::equal(newAnnot.m_offset, -1))

както беше посочено, това винаги е невярно, тъй като size_t не може да съхранява -1. Но сравнението няма да създаде никакви предупреждения, тъй като обработва различни типове правилно и безопасно. Освен това има

сладко::(по-малко|по-малкоравно|неравно|по-голямо|по-голяморавно)

person burner    schedule 09.04.2015

-1 е от тип int. Трябва да го конвертирате в std::size_t или unsigned int чрез static_cast, преди да го сравните.

person Brandon Kohn    schedule 02.08.2014
comment
Да, така е. Но сравняването на променлива size_t по начина: if(newAnnot.m_offset == std::static_cast<size_t>(-1)) също е много неудобно. - person Chen Gupta; 02.08.2014
comment
Съгласен съм, че е, но имате малко възможности, когато започнете от -1. - person Brandon Kohn; 02.08.2014

Тези данни трябва да бъдат ssize_t вместо това, ако -1 е легална стойност. Прехвърлянето на -1 към size_t е просто измама на компилатора и налагане на специално значение на иначе правилната стойност, макар и много голяма, за size_t.

Ако настоявате да използвате най-високата стойност за означаване на „невалиден“, използвайте SIZE_MAX вместо -1.

person Non-maskable Interrupt    schedule 02.08.2014
comment
Е, това е интересен начин за справяне с проблема и мисля, че може да бъде опция в този случай. Въпреки това се казва, че ssize_t е разширение, не е включено в стандарта, следователно не е преносимо в други случаи. - person Chen Gupta; 02.08.2014
comment
Между другото, мисля, че измамният компилатор с -1 cast със сигурност не е добър. Относно специалното значение: std::string::npos налага специално значение на най-голямата стойност на size_t, така че изглежда като законен начин. - person Chen Gupta; 02.08.2014
comment
std::string::npos е просто статичен size_t с присвоен -1. Няма нищо "измама" в присвояването/кастирането -1 на size_t. - person Brandon Kohn; 02.08.2014
comment
IMO има много начини, по които можете да излъжете компилатор и той изгражда грозен код, който работи, един от начините е да кажете на компилатора, че size_t (или всякакви неподписани примитиви) има стойност -1. Вместо това използвайте SIZE_MAX. - person Non-maskable Interrupt; 02.08.2014