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

Я рефакторинг библиотеки и пытаюсь избавиться от многих предупреждений 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()) очень неудобно из-за сложности и длины этого выражения.

Это хороший способ использовать значение SIZE_MAX, определенное в стиле C, или лучше создать собственную константу, например 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. Но сравнение не создаст никаких предупреждений, так как правильно и безопасно обрабатывает разные типы. Кроме того, есть

сладкий::(меньше|lessEqual|notEqual|больше|большеEqual)

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 — это, конечно, нехорошо. О специальном значении: 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