Часто, OutputCaching может быть самым быстрым и эффективным, но только когда он отвечает Вашим требованиям. Никакой смысл в наличии быстро эффективного, если это неправильно! ;)
В этом случае, это кажется, что кэширование на слое данных корректно, потому что у Вас есть сложные потребности кэширования. Иногда, можно объединить два, если набор параметров, которые управляют тем, что производит, кэшируется, просто.
#define ISVARSIGNED(V) ((V)<0 || (-V)<0 || (V-1)<0)
не меняет значение V. Третий тест обрабатывает случай, когда V == 0.
В моем компиляторе (gcc / cygwin) это работает для int
и long
, но не для char
или short
.
#define ISVARSIGNED(V) ((V)-1<0 || -(V)-1<0)
также выполняет свою работу в двух тестах.
Если вы используете GCC, вы можете использовать ключевое слово typeof
, чтобы не перезаписывать value:
#define ISVARSIGNED(V) ({ typeof (V) _V = -1; _V < 0 ? 1 : 0 })
Это создает временную переменную _V
, которая имеет тот же тип, что и V
.
Что касается переносимости, я не знаю. Он будет работать на машине с двумя комплиментами (то есть со всем, на чем ваш код когда-либо будет работать, по всей вероятности), и я верю, что он также будет работать на машине комплиментов и знаков и величин. В качестве примечания: если вы используете typeof
, вы можете преобразовать -1
в typeof (V)
, чтобы сделать его более безопасным (т.е. с меньшей вероятностью срабатывания) предупреждения).
#define ISVARSIGNED(V) ((-(V) < 0) != ((V) < 0))
Без уничтожения значения переменной. Но не работает для значений 0.
А как насчет:
#define ISVARSIGNED(V) (((V)-(V)-1) < 0)
Отличительной особенностью математики со знаком / без знака является то, что при сдвиге вправо числа со знаком копируется самый старший бит. Когда вы сдвигаете беззнаковое число, новые биты равны 0.
#define HIGH_BIT(n) ((n) & (1 << sizeof(n) * CHAR_BITS - 1))
#define IS_SIGNED(n) (HIGH_BIT(n) ? HIGH_BIT(n >> 1) != 0 : HIGH_BIT(~n >> 1) != 0
По сути, этот макрос использует условное выражение, чтобы определить, установлен ли старший бит числа. Если это не так, макрос устанавливает его путем побитового отрицания числа. Мы не можем выполнить арифметическое отрицание, потому что -0 == 0. Затем мы сдвигаемся вправо на 1 бит и проверяем, произошло ли расширение знака.
Это предполагает арифметику дополнения до 2, но обычно это безопасное предположение.
Другой подход ко всем ответам типа «сделай это отрицательным»:
#define ISVARSIGNED(V) (~(V^V)<0)
Таким образом, нет необходимости иметь особые случаи для разных значений V, поскольку ∀ V ∈ ℤ, V ^ V = 0.
Это простое решение не имеет побочных эффектов, в том числе то, что ссылка на v выполняется только один раз (что важно в макросе). Мы используем расширение gcc "typeof" для получения типа v, а затем приводим -1 к этому типу:
#define IS_SIGNED_TYPE(v) ((typeof(v))-1 <= 0)
Это <=, а не просто <, чтобы избежать предупреждений компилятора в некоторых случаях (если включено).
Зачем вам нужен макрос? Для этого отлично подходят шаблоны:
template <typename T>
bool is_signed(T) {
static_assert(std::numeric_limits<T>::is_specialized, "Specialize std::numeric_limits<T>");
return std::numeric_limits<T>::is_signed;
}
Который будет работать "из коробки" для всех основных интегральных типов. Он также завершится ошибкой во время компиляции указателей, чего, вероятно, не будет в версии, использующей только вычитание и сравнение.
РЕДАКТИРОВАТЬ : Ой, вопрос требует C. Тем не менее, шаблоны - хороший способ: P