Как определить отрицательное число, присвоенное size_t?

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

std::size_t foo = -42;

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

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

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

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

Изменение его на ptrdiff_t является хрупким и иногда сломанным.

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

Ответ 1

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

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

Ответ 2

Следующий фрагмент из частной библиотеки.

#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))

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