整数类型(或任何类型)的大小以char
/bytes为单位很容易计算为sizeof(type)
。一个常见的习惯用法是乘以CHAR_BIT
来找到类型占用的位数,但在使用填充位的实现中,这将不等于值位的 width。更糟糕的是,代码如下:
x>>CHAR_BIT*sizeof(type)-1
字符串
如果CHAR_BIT*sizeof(type)
大于type
的实际宽度,则实际上可能具有未定义的行为。
为了简单起见,让我们假设我们的类型是无符号的。那么type
的宽度是ceil(log2((type)-1)
。有没有办法将这个值计算为常量表达式?
7条答案
按热度按时间ulydmbyx1#
有一个类似于函数的宏可以确定整数类型的值位,但前提是你已经知道该类型的最大值。是否会得到编译时常量取决于你的编译器,但我猜在大多数情况下答案是肯定的。
感谢Hallvard B. Furuseth在回复question on comp.lang.c时发布的类似IMAX_BITS()函数的宏
字符串
IMAX_BITS(INT_MAX)计算int中的位数,IMAX_BITS((unsigned_type)-1)计算unsigned_type中的位数。除非有人实现4GB整数,否则:-)
感谢Eric Sosman的这个[替代版本](http://groups.google.com/group/comp.lang.c/msg/e998153ef07ff04b?dmode = source),它应该可以在2040位以下工作:(编辑2011年1月3日11:30 PM EST:原来这个版本也是由Hallvard B. Furuseth编写的)
**请记住,尽管无符号整数类型的宽度等于值位数,但有符号整数类型的宽度大于值位数(§6.2.6.2/6)。**这一点特别重要,因为在我对您的问题的原始评论中,我错误地指出IMAX_BITS()宏在实际计算值位数时计算宽度。对此表示抱歉!
例如
IMAX_BITS(INT64_MAX)
将创建一个编译时常量63。然而,在这个例子中,我们处理的是一个有符号类型,所以如果你想要一个int64_t的实际宽度,当然是64,你必须加1来解释符号位。在comp.lang.c的一个单独的讨论中,一个名为blargg的用户给出了宏如何工作的分解:
Re: using pre-processor to count bits in integer types...的
请注意,该宏仅适用于2^n-1个值(即二进制中全为1),正如任何MAX值所预期的那样。还要注意,虽然很容易获得无符号整数类型的最大值的编译时常数,(
IMAX_BITS((unsigned type)-1)
),在写这篇文章的时候,我不知道有什么方法可以在不调用实现的情况下对有符号整数类型做同样的事情-定义的行为。如果我发现了,我会回答我自己的相关问题,在这里:C question: off_t (and other signed integer types) minimum and maximum values - Stack Overflow的
ukqbszuj2#
将
<limits.h>
中的宏与特定整数宽度的已知最大值进行比较:字符串
gcmastyq3#
第一种方法,如果你知道你有什么标准类型(所以你的类型不是
typedef
),使用{U}INT_MAX
宏并检查可能的大小。如果你没有这个,对于unsigned类型,这在概念上相对容易。对于你喜欢的类型
T
,只需执行(T)-1
,然后执行一个怪物测试宏,用?:
检查所有可能的值。因为这些只是编译时常量表达式,任何像样的编译器都会优化它,只留下你感兴趣的值。这在
#if
等中不起作用,因为类型转换,但这不能以简单的方式避免。对于有符号类型,这就更复杂了。对于至少像
int
这样宽的类型,你可以希望做一个技巧来提升到相应的无符号类型,然后获得该类型的宽度。但是要知道你的有符号类型是否只少了一个值位,不,我不认为有一个泛型表达式可以知道这一点。**编辑:**只是为了说明这一点,我给予一些摘录,你可以做些什么,使这种方法(对于无符号类型)在P99中不生成太大的表达式,我有这样的东西
字符串
其中魔法常量在开始时用一个#if序列定义。在那里重要的是不要暴露太大的常量给编译器,因为编译器不能处理它们。
型
gkl3eglg4#
你可以在运行时用一个简单的循环计算它,定义良好,没有UB的危险:
字符串
最简单的方法是在单元测试中检查value_bits是否与当前的INT_WIDTH定义相同(你有它们,对吗?)。
如果你真的需要在编译时计算它,我会使用给定的#if-#elif级联之一,测试UINT_MAX或你的目标系统。
你要它做什么?也许是雅尼?
wlwcrazw5#
一般的观察是,如果你在计算中依赖于数据类型的宽度,你应该使用
<stdint.h>
中定义的显式宽度数据类型,例如uint32_t
。试图计算标准类型中的字节数是在回避一个问题,即在溢出的情况下,您的“可移植”代码会做什么。
yduiuuwa6#
是的,因为对于所有实际目的,可能的宽度的数量是有限的:
字符串
goucqfw67#
通常,
int
的大小对于给定的编译器/平台是已知的。如果你有标识编译器/平台的宏,那么你可以用它们来有条件地定义INT_WIDTH
。您可以查看
<sys/types.h>
及其依赖项作为示例。