Как бы вы пишете (в C/С++) макрос, который проверяет, является ли целочисленный тип (заданный как параметр) подписанным или неподписанным?
#define is_this_type_signed (my_type) ...
Как бы вы пишете (в C/С++) макрос, который проверяет, является ли целочисленный тип (заданный как параметр) подписанным или неподписанным?
#define is_this_type_signed (my_type) ...
Если вам нужен простой макрос, это должно сделать трюк:
#define is_type_signed(my_type) (((my_type)-1) < 0)
В С++ используйте std::numeric_limits<type>::is_signed
.
#include <limits>
std::numeric_limits<int>::is_signed - returns true
std::numeric_limits<unsigned int>::is_signed - returns false
См. http://msdn.microsoft.com/en-us/library/85084kd6(VS.80).aspx.
Если вам нужен макрос, то это должно сделать трюк:
#define IS_SIGNED( T ) (((T)-1)<0)
В принципе, приведите -1 к вашему типу и посмотрите, все ли он -1. В С++ вам не нужен макрос. Просто #include <limits>
и:
bool my_type_is_signed = std::numeric_limits<my_type>::is_signed;
Ваше требование не является лучшим, но если вы хотите взломать определение, одним из вариантов может быть:
#define is_numeric_type_signed(typ) ( (((typ)0 - (typ)1)<(typ)0) && (((typ)0 - (typ)1) < (typ)1) )
Однако это не считается приятным или переносимым любыми способами.
На самом деле я сегодня просто задавался вопросом о том же. Кажется, что работает следующее:
#define is_signed(t) ( ((t)-1) < 0 )
Я тестировал с помощью:
#include <stdio.h>
#define is_signed(t) ( ((t)-1) < 0 )
#define psigned(t) printf( #t " is %s\n", is_signed(t) ? "signed" : "unsigned" );
int
main(void)
{
psigned( int );
psigned( unsigned int );
}
который печатает:
int is signed
unsigned int is unsigned
В С++ вы можете:
bool is_signed = std::numeric_limits<typeof(some_integer_variable)>::is_signed;
numeric_limits определяется в заголовке <limits> .
Althout typeof
не является законным С++ на данный момент, вы можете использовать вычет шаблона. См. Пример кода ниже:
#include <iostream>
#include <limits>
template <typename T>
bool is_signed(const T& t)
{
return std::numeric_limits<T>::is_signed;
}
int main()
{
std::cout <<
is_signed(1) << " " <<
is_signed((unsigned char) 0) << " " <<
is_signed((signed char) 0) << std::endl;
}
Этот код напечатает
1 0 1
Для С++ существует boost:: is_unsigned <T> . Мне любопытно, зачем вам это нужно, хотя есть несколько веских причин ИМХО.
Более "современный" подход заключается в использовании type_traits
:
#include <type_traits>
#include <iostream>
int main()
{
std::cout << ( std::is_signed<int>::value ? "Signed" : "Unsigned") <<std::endl;
}
Вы можете сделать это лучше с помощью функции шаблона, меньше макросов неприятного бизнеса.
template <typename T>
bool IsSignedType()
{
// A lot of assumptions on T here
T instanceAsOne = 1;
if (-instanceAsOne > 0)
{
return true;
}
else
{
return false;
}
}
Простите форматирование...
Я бы попробовал это и посмотрел, работает ли он...
В C вы не можете написать макрос, который работает с пока неизвестным typedef основных целых типов.
В С++ вы можете до тех пор, пока ваш тип представляет собой фундаментальный целочисленный тип или typedef основного целочисленного типа. Вот что вы бы сделали в С++:
template <typename T>
struct is_signed_integer
{
static const bool value = false;
};
template <>
struct is_signed_integer<int>
{
static const bool value = true;
};
template <>
struct is_signed_integer<short>
{
static const bool value = true;
};
template <>
struct is_signed_integer<signed char>
{
static const bool value = true;
};
template <>
struct is_signed_integer<long>
{
static const bool value = true;
};
// assuming your C++ compiler supports 'long long'...
template <>
struct is_signed_integer<long long>
{
static const bool value = true;
};
#define is_this_type_signed(my_type) is_signed_integer<my_type>::value