C问题:off_t(和其他有符号整数类型)的最小值和最大值

Ano*_*Guy 11 c binary bit-manipulation bitwise-operators

我偶尔会遇到一个整数类型(例如POSIX有符号整数类型off_t),其中有一个宏的最小值和最大值是有帮助的,但我不知道如何制作一个真正可移植的宏.


对于无符号整数类型,我一直认为这很简单.0最小和~0最大.我已经阅读了几个不同的SO线程,建议使用-1而不是~0为了便携性.这里有一个有争议的有趣线程:
c ++ - 使用-1将所有位设置为true是否安全?- 堆栈溢出

然而,即使在阅读了这个问题后,我仍然感到困惑.另外,我正在寻找兼容C89和C99的东西,所以我不知道是否适用相同的方法.说我有一种类型uint_whatever_t.难道我不能先转为0然后按位补码?这样可以吗?:

#define UINT_WHATEVER_T_MAX ( ~ (uint_whatever_t) 0 )
Run Code Online (Sandbox Code Playgroud)


有符号整数类型看起来像是一个更难以破解的坚果.我已经看到了几种不同的可能解决方案,但只有一种似乎是可移植的.无论是那个还是不正确的.我在谷歌搜索OFF_T_MAX和OFF_T_MIN时找到了它.感谢Christian Biere:

#define MAX_INT_VAL_STEP(t) \
    ((t) 1 << (CHAR_BIT * sizeof(t) - 1 - ((t) -1 < 1))) 

#define MAX_INT_VAL(t) \
    ((MAX_INT_VAL_STEP(t) - 1) + MAX_INT_VAL_STEP(t))

#define MIN_INT_VAL(t) \
    ((t) -MAX_INT_VAL(t) - 1)

[...]
#define OFF_T_MAX MAX_INT_VAL(off_t) 
Run Code Online (Sandbox Code Playgroud)


我找不到关于C89中不同允许类型的有符号整数表示的任何内容,但C99在§J.3.5中有关于整数可移植性问题的注释:

是否使用符号和幅度,二进制补码或一对补码表示有符号整数类型,以及非常值是陷阱表示还是普通值(6.2.6.2).

这似乎意味着只能使用那三个列出的签名数字表示.暗示是否正确,并且上面的宏是否与所有三种表示兼容?


其他想法:如果有填充位
,似乎类似函数的宏MAX_INT_VAL_STEP()会给出不正确的结果.我想知道是否有任何办法解决这个问题.

通过维基百科上的带符号数字表示,我发现对于所有三个有符号整数表示,任何有符号整数类型的MAX都将是:
符号位关闭,所有值位开启(全部三个)
并且其MIN将是:
符号位开启,全部值符号打开(符号和幅度)
符号位打开,所有值位关闭(1 /二进制补码)

我想我可以通过这样做来测试符号和幅度:

#define OFF_T_MIN ( ( ( (off_t)1 | ( ~ (off_t) -1 ) ) != (off_t)1 ) ? /* sign and magnitude minimum value here */ : /* ones and twos complement minimum value here */ )
Run Code Online (Sandbox Code Playgroud)

那么当符号和幅度是符号位,并且所有值位都不是off_t的最小值,在这种情况下是~ (off_t) 0?对于一些/两个补码最小值,我需要一些方法来关闭所有的值位,但保持符号位.不知道如何在不知道值位数的情况下执行此操作.标志位是否保证始终比最重要的值位更重要?

谢谢,如果帖子太长,请告诉我



编辑12/29/2010美国东部时间下午5点:
如下所述,通过ephemient获得无符号类型最大值,(unsigned type)-1更正确~0甚至更正确~(unsigned type)0.从使用-1时我可以收集到的它与0-1相同,它总是导致无符号类型的最大值.

此外,因为可以确定无符号类型的最大值,所以可以确定无符号类型中有多少个值位.感谢Hallvard B. Furuseth为他在回复comp.lang.c上的问题时发布的类似IMAX_BITS()函数的宏.

/* Number of bits in inttype_MAX, or in any (1<<b)-1 where 0 <= b < 3E+10 */
#define IMAX_BITS(m) ((m) /((m)%0x3fffffffL+1) /0x3fffffffL %0x3fffffffL *30 \
                  + (m)%0x3fffffffL /((m)%31+1)/31%31*5 + 4-12/((m)%31+3))
Run Code Online (Sandbox Code Playgroud)

IMAX_BITS(INT_MAX)计算int中的位数,IMAX_BITS((unsigned_type)-1)计算unsigned_type中的位数.直到有人实现4千兆字节的整数,无论​​如何:-)

然而,我的问题的核心仍然没有答案:如何通过宏确定签名类型的最小值和最大值.我还在调查这个.也许答案是没有答案.

如果您在大多数情况下没有在StackOverflow上查看此问题,则在接受之前您无法看到建议的答案.建议在StackOverflow上查看此问题.

eph*_*ent 5

令人惊讶的是,C int在算术运算之前提升类型,结果至少是int大小.(类似的奇怪包括'a'具有类型的字符文字int,而不是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 */
Run Code Online (Sandbox Code Playgroud)

所以#define UINT_WHATEVER_T_MAX ( ~ (uint_whatever_t) 0 )不一定好.


R..*_*R.. 5

我相信我终于解决了这个问题,但解决方案只能在configure时间,而不是编译时或运行时使用,所以它仍然不是主意.这里是:

HEADERS="#include <sys/types.h>"
TYPE="off_t"
i=8
while : ; do
printf "%s\nstruct { %s x : %d; };\n" "$HEADERS" "$TYPE" $i > test.c
$CC $CFLAGS -o /dev/null -c test.c || break
i=$(($i+1))
done
rm test.c
echo $(($i-1))
Run Code Online (Sandbox Code Playgroud)

这个想法来自6.7.2.1第3段:

指定位字段宽度的表达式应为整数常量表达式,其非负值不超过将指定的类型的对象的宽度,省略冒号和表达式.如果该值为零,则声明不应具有声明者.

如果这会导致在编译时解决问题的任何想法,我会很高兴.


tle*_*nes -1

您可能想查看 limit.h (在 C99 中添加),该标头提供了应设置为匹配编译器范围的宏。(它与编译器附带的标准库一起提供,或者第三方标准库替换负责使其正确)