C question: off_t (and other signed integer types) minimum and maximum values

后端 未结 9 1003
耶瑟儿~
耶瑟儿~ 2020-12-06 05:58

I occasionally will come across an integer type (e.g. POSIX signed integer type off_t) where it would be helpful to have a macro for its minimum and maximum val

相关标签:
9条回答
  • 2020-12-06 06:17

    You probably want to look at limits.h (added in C99) this header provides macros that should be set to match the compiler's ranges. (either it is provided along with the Standard library that came with the compiler, or a third party standard library replacement is responsible for getting it right)

    0 讨论(0)
  • 2020-12-06 06:19

    Surprisingly, C promotes types up to int before arithmetic operations, with results being at least int sized. (Similarly oddities include 'a' character literal having type int, not char.)

    int a = (uint8_t)1 + (uint8_t)-1;
       /* = (uint8_t)1 + (uint8_t)255 = (int)256 */
    int b = (uint8_t)1 + ~(uint8_t)0;
       /* = (uint8_t)1 + (int)-1 = (int)0 */
    

    So #define UINT_WHATEVER_T_MAX ( ~ (uint_whatever_t) 0 ) isn't necessarily okay.

    0 讨论(0)
  • 2020-12-06 06:19

    I have used the following pattern to solve the problem (assuming there are no padding bits):

    ((((type) 1 << (number_of_bits_in_type - 1)) - 1) << 1) + 1
    

    The number_of_bits_in_type is derived as CHAR_BIT * sizeof (type) as in the other answers.

    We basically "nudge" the 1 bits into place, while avoiding the sign bit.

    You can see how this works. Suppose that the width is 16 bits. Then we take 1 and shift it left by 16 - 2 = 14, producing the bit pattern 0100000000000000. We carefully avoided shifting a 1 into the sign bit. Next, we subtract 1 from this, obtaining 0011111111111111. See where this is going? We shift this left by 1 obtaining 0111111111111110, again avoiding the sign bit. Finally we add 1, obtaining 0111111111111111, which is the highest signed 16 bit value.

    This should work fine on one's complement and sign-magnitude machines, if you work in a museum where they have such things. It doesn't work if you have padding bits. For that, probably all you can do is #ifdef, or switch to alternative configuration mechanisms outside of the compiler and preprocessor.

    0 讨论(0)
  • 2020-12-06 06:20

    It's technically not a macro, but in practice the following should always be folded into a constant minimum for off_t, or any signed type, regardless of sign representation. Although I'm not sure what doesn't use two's compliment, if anything.

    POSIX requires a signed integer type for off_t, so the C99 signed exact width values should be sufficient. Some platforms actually define OFF_T_MIN (OSX), but POSIX unfortunately doesn't require it.

    #include <stdint.h>
    #include <assert.h>
    
    #include <sys/types.h>
    
      assert(sizeof(off_t) >= sizeof(int8_t) && sizeof(off_t) <= sizeof(intmax_t));
    
      const off_t OFF_T_MIN = sizeof(off_t) == sizeof(int8_t)   ? INT8_MIN    :
                              sizeof(off_t) == sizeof(int16_t)  ? INT16_MIN   :
                              sizeof(off_t) == sizeof(int32_t)  ? INT32_MIN   :
                              sizeof(off_t) == sizeof(int64_t)  ? INT64_MIN   :
                              sizeof(off_t) == sizeof(intmax_t) ? INTMAX_MIN  : 0;
    

    The same is usable to obtain the maximum value.

      assert(sizeof(off_t) >= sizeof(int8_t) && sizeof(off_t) <= sizeof(intmax_t));
    
      const off_t OFF_T_MAX = sizeof(off_t) == sizeof(int8_t)   ? INT8_MAX    :
                              sizeof(off_t) == sizeof(int16_t)  ? INT16_MAX   :
                              sizeof(off_t) == sizeof(int32_t)  ? INT32_MAX   :
                              sizeof(off_t) == sizeof(int64_t)  ? INT64_MAX   :
                              sizeof(off_t) == sizeof(intmax_t) ? INTMAX_MAX  : 0;
    

    This could be turned into a macro using autoconf or cmake though.

    0 讨论(0)
  • 2020-12-06 06:24

    Since C11 you can use _Generic to find the underlying type. Before then __builtin_choose_expr with __typeof and __builtin_types_compatible_p was fairly portable.

    If you don't want to use any of those, you could guess the type based on its size and signedness.

    #include <stdio.h>
    #include <limits.h>
    #define TP_MAX(Tp) ((Tp)-1>0 ? ( \
                            1==sizeof(Tp) ? ((Tp)2==1?1:UCHAR_MAX) \
                            : sizeof(unsigned short)==sizeof(Tp) ? USHRT_MAX \
                            : sizeof(unsigned int)==sizeof(Tp) ? UINT_MAX \
                            : sizeof(unsigned long)==sizeof(Tp) ? ULONG_MAX \
                            : sizeof(unsigned long long)==sizeof(Tp) ? ULLONG_MAX : 0 \
                       ) :  ( 1==sizeof(Tp) ? SCHAR_MAX \
                            : sizeof(short)==sizeof(Tp) ? SHRT_MAX \
                            : sizeof(int)==sizeof(Tp) ? INT_MAX \
                            : sizeof(long)==sizeof(Tp) ? LONG_MAX \
                            : sizeof(long long)==sizeof(Tp) ? LLONG_MAX : 0)) \
    
    
    #define STC_ASSERT(X) ((void)(sizeof(struct { int stc_assert:(X)?1:-1; })))
    
    int main()
    {
        STC_ASSERT(TP_MAX(signed char)==SCHAR_MAX);
        STC_ASSERT(TP_MAX(short)==SHRT_MAX);
        STC_ASSERT(TP_MAX(int)==INT_MAX);
        STC_ASSERT(TP_MAX(long)==LONG_MAX);
        STC_ASSERT(TP_MAX(long long)==LLONG_MAX);
        STC_ASSERT(TP_MAX(unsigned char)==UCHAR_MAX);
        STC_ASSERT(TP_MAX(unsigned short)==USHRT_MAX);
        STC_ASSERT(TP_MAX(unsigned int)==UINT_MAX);
        STC_ASSERT(TP_MAX(unsigned long)==ULONG_MAX);
        STC_ASSERT(TP_MAX(unsigned long long)==ULLONG_MAX);
    }
    

    (If you want to do it even without limits.h, please check out my answer at https://stackoverflow.com/a/53470064/1084774).

    0 讨论(0)
  • 2020-12-06 06:26

    For sign-magnitude representations, it's fairly easy (for types at least as wide as int, anyway):

    #define SM_TYPE_MAX(type) (~(type)-1 + 1)
    #define SM_TYPE_MIN(type) (-TYPE_MAX(type))
    

    Unfortunately, sign-magnitude representations are rather thin on the ground ;)

    0 讨论(0)
提交回复
热议问题