Как определить отрицательное число, присвоенное размеру t?

это объявление компилируется без предупреждений в g++ - pedantic-Wall (версия 4.6.3):

std::size_t foo = -42;

менее заметно фиктивным является объявление функции с аргументом size_t и вызов ее с отрицательным значением. Может ли такая функция защитить от непреднамеренного отрицательного аргумента (который появляется как umpteen quintillion, подчиняясь §4.7/2)?

неполные ответы:

просто изменение size_t на (signed) long отбрасывает семантику и другие преимущества в size_t.

изменение его на ssize_t-это просто POSIX, а не стандарт.

изменение его на ptrdiff_t хрупкое и иногда сломанное.

тестирование для огромных значений (набор битов высокого порядка и т. д.) является произвольным.

2 ответов


проблема с выдачей предупреждения для этого заключается в том, что это не неопределенное поведение в соответствии со стандартом. Если вы преобразуете подписанное значение в тип без знака того же размера, вы можете позже преобразовать его обратно в подписанное значение и получить исходное значение в любом компиляторе, совместимом со стандартами.

кроме того, использование отрицательных значений, преобразованных в size_t, является довольно распространенной практикой для различных условий ошибки - многие системные вызовы возвращают unsigned (size_t или off_t) значение для успеха или -1 (преобразованный в unsigned) для ошибки. Поэтому добавление такого предупреждения в компилятор вызовет ложные предупреждения для многих существующих кодов. POSIX пытается кодифицировать это с помощью ssize_t, но это прерывает вызовы, которые могут быть успешными с возвращаемым значением, большим, чем максимальное значение со знаком для ssize_t.


следующий отрывок из частной библиотеки.

#include <limits.h>

#if __STDC__ == 1 && __STDC_VERSION__ >= 199901L || \
    defined __GNUC__ || defined _MSC_VER
    /* Has long long. */
    #ifdef __GNUC__
        #define CORE_1ULL __extension__ 1ULL
    #else
        #define CORE_1ULL 1ULL
    #endif
    #define CORE_IS_POS(x) ((x) && ((x) & CORE_1ULL << (sizeof (x)*CHAR_BIT - 1)) == 0)
    #define CORE_IS_NEG(x) (((x) & CORE_1ULL << (sizeof (x)*CHAR_BIT - 1)) != 0)
#else
    #define CORE_IS_POS(x) ((x) && ((x) & 1UL << (sizeof (x)*CHAR_BIT - 1)) == 0)
    #define CORE_IS_NEG(x) (((x) & 1UL << (sizeof (x)*CHAR_BIT - 1)) != 0)
#endif

#define CORE_IS_ZPOS(x) (!(x) || CORE_IS_POS(x))
#define CORE_IS_ZNEG(x) (!(x) || CORE_IS_NEG(x))

Это должно работать со всеми беззнаковые типы.