Jump to content

    
Sign in to follow this  
Dimoza

Получение предельно допустимых значений переменной

Recommended Posts

Здравствуйте. Подскажите, возможно ли в С/С++ красиво реализовать следующее:

 

Есть некая переменная, которой во время работы программы хочется присвоить максимально (минимально) допустимое значение. Если мы например решили, что переменная типа signed char, то ясное дело, можно просто присваивать +127 или -128. Но если вдруг по каким либо причинам тип изменили на signed int, то нужны уже другие значения, +32767 и -32768. Хорошо если при этом не забыли пробежать по коду и везде поменять. А если забыли? Как бы это покрасивше автоматизировать? Вроде бы корректный путь написать что-то вроде:

signed int AD_Umax;
AD_Umax =  (1<<(sizeof(AD_Umax)*8-1))-1;

Но компилятор в этом случае выдаёт предупреждение о том, что "превышено максимально допустимое значение", что логично: в процессе вычисления есть промежуточная величина, выходящая за допустимые для данного типа пределы.

Share this post


Link to post
Share on other sites

Можно присваивать ULLONG_MAX (limits.h). Всё лишнее будет отброшено. Подходит только беззнаковым типам. Для знаковых надо сбросить старший бит, а то получится -1.

Или memset(&var, 0xFF, sizeof var).

Share this post


Link to post
Share on other sites
...возможно ли в С/С++...Хорошо если при этом не забыли пробежать по коду и везде поменять. А если забыли?...

 

вообщето условие перечёркивает вопрос. если си плас плас юзаете по назначению (ООА & ООП) - то и проблем не должно быть по определению (за рамками файла). иначе - менять консерваторию, либо писать на азме.

 

Share this post


Link to post
Share on other sites

То что консерватория не по феншую, это я понимаю. В итоге скорее всего перепишу код, чтобы таких заморочек не было.

 

А за идеи большое спасибо! Всегда интересно, какие "козьи тропы" существуют.

Share this post


Link to post
Share on other sites

Дима, привет!

Только это смог изобразить, поэтому смену знаковости аргумента не отловит :

#define MAX_UNSIGNED(X) \
    ((sizeof(X) == 1)?   0xffU         : \
     (sizeof(X) == 2)?   0xffffU       : \
     (sizeof(X) == 4)?   0xffffffffUL  : 0U)

#define MAX_SIGNED(X) \
    ((sizeof(X) == 1)?   0x7f          : \
     (sizeof(X) == 2)?   0x7fff        : \
     (sizeof(X) == 4)?   0x7fffffffL   : 0L)

#define MIN_UNSIGNED(X)                0U

#define MIN_SIGNED(X) \
    ((sizeof(X) == 1)?  -128          : \
     (sizeof(X) == 2)?  -32768        : \
     (sizeof(X) == 4)?  -2147483648L  : 0L)

Ещё немного подумал и нашёл решение для gcc!

#define IS_UNSIGNED(X)\
({ \
    const typeof(X) __x = 0;       \
    const typeof(X) __y = __x-1;   \
    (__y>0);                       \
})

#define MIN_OF_TYPE(X) ((IS_UNSIGNED(X))?  MIN_UNSIGNED(X) : MIN_SIGNED(X))
#define MAX_OF_TYPE(X) ((IS_UNSIGNED(X))?  MAX_UNSIGNED(X) : MAX_SIGNED(X))

И ещё немного подумал и для gcc написал ещё проще:

#define MAX_OF_TYPE(X) \
    ((__builtin_types_compatible_p(typeof(X), int8_t))?     (int8_t)0x7f       : \
     (__builtin_types_compatible_p(typeof(X), int16_t))?   (int16_t)0x7fff     : \
     (__builtin_types_compatible_p(typeof(X), int32_t))?   (int32_t)0x7fffffff : \
     (__builtin_types_compatible_p(typeof(X), uint8_t))?   (uint8_t)0xff       : \
     (__builtin_types_compatible_p(typeof(X), uint16_t))? (uint16_t)0xffff     : \
     (__builtin_types_compatible_p(typeof(X), uint32_t))? (uint32_t)0xffffffff : 0)

#define MIN_OF_TYPE(X) \
    ((__builtin_types_compatible_p(typeof(X), int8_t))?     (int8_t)0x80       : \
     (__builtin_types_compatible_p(typeof(X), int16_t))?   (int16_t)0x8000     : \
     (__builtin_types_compatible_p(typeof(X), int32_t))?   (int32_t)0x80000000 : \
     (__builtin_types_compatible_p(typeof(X), uint8_t))?   (uint8_t)0x00       : \
     (__builtin_types_compatible_p(typeof(X), uint16_t))? (uint16_t)0x0000     : \
     (__builtin_types_compatible_p(typeof(X), uint32_t))? (uint32_t)0x00000000 : 0)

Share this post


Link to post
Share on other sites

Я для определения предельных значений типов пользуюсь такими С++ шаблонами:

template<class T, T IntegralTypeCheck=T(0)>
struct IsSigned
{
    enum{value = T(-1) < T(0)};
};

template<class T>
struct MinValue
{
    static const T value = IsSigned<T>::value ? ( T(1) << (sizeof(T)*8 - 1)) : 0;
};

template<class T>
struct MaxValue
{
    static const T value = ~MinValue<T>::value;
};

Работает, естественно, на платформах где в байте 8 бит и с отрицательными числами в дополнительном коде.

Эти шаблоны несложно на макросы переписать, если нужно.

А пользоваться ими примерно так:

    cout << "Min int =\t" <<  MinValue<int>::value << "\tMax int = " << MaxValue<int>::value << endl;
    cout << "Min unsigned =\t" <<  MinValue<unsigned>::value << "\tMax unsigned = " << MaxValue<unsigned>::value << endl;
    cout << "Min long long =\t" <<  MinValue<long long>::value << "\tMax long long = " << MaxValue<long long>::value << endl;
    cout << "Min char =\t" <<  MinValue<char>::value << "\tMax char = " << MaxValue<char>::value << endl;
    cout << "Min short =\t" <<  MinValue<short>::value << "\tMax short = " << MaxValue<short>::value << endl;
    cout << "Min unsigned short =\t" <<  MinValue<unsigned short>::value << "\tMax unsigned short = " << MaxValue<unsigned short>::value << endl;

Edited by neiver

Share this post


Link to post
Share on other sites
А вы попробуйте! Да так чтобы без привязки к gcc...

Попробовал. Получилось. Работает.

#define __IS_SIGNED(TYPE) ((TYPE)(-1) < (TYPE)(0))
#define IS_SIGNED(TYPE) __IS_SIGNED(TYPE)
#define __MIN_VALUE(TYPE) (IS_SIGNED(TYPE) ? ( (TYPE)(1) << (sizeof(TYPE)*8 - 1)) : 0)
#define MIN_VALUE(TYPE) __MIN_VALUE(TYPE)
#define __MAX_VALUE(TYPE) (~MIN_VALUE(TYPE))
#define MAX_VALUE(TYPE) __MAX_VALUE(TYPE)

Можно даже вот так писать:

#define MY_TYPE int
enum Foo
{
    Max = MAX_VALUE(MY_TYPE)
};

Но мне с шаблонами удобнее.

Share this post


Link to post
Share on other sites
Это немного не то...

Вы аргументом передаёте тип, а нужно экземпляр этого типа...

Но и так тоже можно выкрутиться (через typedef).

А вообще очень лаконично сделано!

Share this post


Link to post
Share on other sites

Немножко не совсем определение максимального и минимального значения, но близко

 

Получаю тип переменной по имени на этапе компиляции следующим образом:

template<class T, class U> struct IsSame       { char d;    };
template<class T>          struct IsSame<T, T> { char d[2]; };
template<class T, class U> IsSame<T, U> test(const U&);

#define IS_SAME_TYPE(type, var) (sizeof(test<type>(var)) == sizeof(IsSame<int, int>))

#define GET_STD_TYPE(var) (IS_SAME_TYPE(uint8_t, var)  ? T_U08    : \
                          (IS_SAME_TYPE(int8_t, var)   ? T_S08    : \
                          (IS_SAME_TYPE(uint16_t, var) ? T_U16    : \
                          (IS_SAME_TYPE(int16_t, var)  ? T_S16    : \
                          (IS_SAME_TYPE(uint32_t, var) ? T_U32    : \
                          (IS_SAME_TYPE(int32_t, var)  ? T_S32    : \
                          (IS_SAME_TYPE(uint64_t, var) ? T_U32    : \
                          (IS_SAME_TYPE(int64_t, var)  ? T_S32    : \
                          (IS_SAME_TYPE(char*, var)    ? T_STR    : \
                          (IS_SAME_TYPE(float, var)    ? T_FLOAT  : \
                          (IS_SAME_TYPE(double, var)   ? T_DOUBLE : \
                          T_NONE)))))))))))

По типу сделать определение максимального и минимального значения уже проще будет

gettype.rar

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this