代码之家  ›  专栏  ›  技术社区  ›  R.. GitHub STOP HELPING ICE

编译时有没有办法计算整数类型的宽度?

  •  14
  • R.. GitHub STOP HELPING ICE  · 技术社区  · 14 年前

    整数类型(或任何类型)的大小,单位为 char /字节很容易计算为 sizeof(type) . 一个常见的成语是乘 CHAR_BIT 要查找类型占用的位数,但在使用填充位的实现上,这将不等于 宽度 在价值位中。更糟的是,代码如下:

    x>>CHAR_BIT*sizeof(type)-1
    

    如果 CHAR_BIT*sizeof(type) 大于的实际宽度 type .

    为了简单起见,假设我们的类型是无符号的。那么宽度 类型 ceil(log2((type)-1)

    7 回复  |  直到 14 年前
        1
  •  10
  •   Community CDub    7 年前

    归功于Hallvard B.Furuseth的imax_bits()函数,比如他在回复a时发布的宏 question on comp.lang.c

    /* 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))
    

    imax_bits(int_max)计算int中的位数,imax_bits((unsigned_type)-1)计算unsigned_类型中的位数。直到有人实现4千兆字节的整数,无论如何:—)


    埃里克·索斯曼的功劳 为此 alternate version 它应该在2040位以下工作:
    (编辑2011年1月3日11:30东部时间:原来这个版本也是由Hallvard B.Furuseth编写的)

    /* Number of bits in inttype_MAX, or in any (1<<k)-1 where 0 <= k < 2040 */
    #define IMAX_BITS(m) ((m)/((m)%255+1) / 255%255*8 + 7-86/((m)%255+12))
    


    记住,尽管无符号整数类型的宽度等于值位的数量,但有符号整数类型的宽度要大一点(§6.2.6.2/6)。 这一点非常重要,因为在我对您的问题的原始注释中,我错误地指出IMAX_Bits()宏在计算值位的数量时计算宽度。对不起!

    例如 IMAX_BITS(INT64_MAX) 将创建一个编译时常量63。然而,在这个例子中,我们处理的是一个有符号类型,因此如果您想要一个int64的实际宽度(当然是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

        2
  •  5
  •   Christoph    14 年前

    比较宏的来源 <limits.h> 针对特定整数宽度的已知最大值:

    #include <limits.h>
    
    #if UINT_MAX == 0xFFFF
    #define INT_WIDTH 16
    #elif UINT_MAX == 0xFFFFFF
    #define INT_WIDTH 24
    #elif ...
    #else
    #error "unsupported integer width"
    #endif
    
        3
  •  2
  •   Jens Gustedt    14 年前

    第一种方法,如果你知道你的标准类型(所以你的类型不是 typedef 一起去 {U}INT_MAX 宏并检查可能的大小。

    如果没有,对于无符号类型,这在概念上相对容易。你最喜欢的类型 T 只是做 (T)-1 做一个怪物测试宏,用 ?: . 因为这些都只是编译时常量表达式,所以任何一个合适的编译器都会对其进行优化,只留下您感兴趣的值。

    这不管用 #if 等等,因为类型转换,但这是无法避免的简单方法。

    对于签名类型,这更为复杂。对于宽度至少与 int 您可以希望执行一个技巧来提升到相应的无符号类型,然后获取该类型的宽度。但是要知道您的签名类型是否只少一个值,不,我不认为有一个通用表达式可以知道这一点。

    编辑: 为了说明这一点,我给你一些摘录 可以使此方法(对于无符号类型)不生成 中的大型表达式 P99 我有类似的东西

    #ifndef P99_HIGH2
    # if P99_UINTMAX_WIDTH == 64
    #  define P99_HIGH2(X)                                         \
    ((((X) & P00_B0) ? P00_S0 : 0u)                              \
     | (((X) & P00_B1) ? P00_S1 : 0u)                            \
     | (((X) & P00_B2) ? P00_S2 : 0u)                            \
     | (((X) & P00_B3) ? P00_S3 : 0u)                            \
     | (((X) & P00_B4) ? P00_S4 : 0u)                            \
     | (((X) & P00_B5) ? P00_S5 : 0u))
    # endif
    #endif
    #ifndef P99_HIGH2
    # if P99_UINTMAX_WIDTH <= 128
    #  define P99_HIGH2(X)                                         \
    ((((X) & P00_B0) ? P00_S0 : 0u)                              \
     | (((X) & P00_B1) ? P00_S1 : 0u)                            \
     | (((X) & P00_B2) ? P00_S2 : 0u)                            \
     | (((X) & P00_B3) ? P00_S3 : 0u)                            \
     | (((X) & P00_B4) ? P00_S4 : 0u)                            \
     | (((X) & P00_B5) ? P00_S5 : 0u)                            \
     | (((X) & P00_B6) ? P00_S6 : 0u))
    # endif
    #endif
    

    其中magic常量是用一个if序列定义的, 开始。在那里,重要的是不要暴露太大的常量 对于无法处理它们的编译器。

    /* The preprocessor always computes with the precision of uintmax_t */
    /* so for the preprocessor this is equivalent to UINTMAX_MAX       */
    #define P00_UNSIGNED_MAX ~0u
    
    #define P00_S0 0x01
    #define P00_S1 0x02
    #define P00_S2 0x04
    #define P00_S3 0x08
    #define P00_S4 0x10
    #define P00_S5 0x20
    #define P00_S6 0x40
    
    /* This has to be such ugly #if/#else to ensure that the            */
    /* preprocessor never sees a constant that is too large.            */
    #ifndef P99_UINTMAX_MAX
    # if P00_UNSIGNED_MAX == 0xFFFFFFFFFFFFFFFF
    #  define P99_UINTMAX_WIDTH 64
    #  define P99_UINTMAX_MAX 0xFFFFFFFFFFFFFFFFU
    #  define P00_B0 0xAAAAAAAAAAAAAAAAU
    #  define P00_B1 0xCCCCCCCCCCCCCCCCU
    #  define P00_B2 0xF0F0F0F0F0F0F0F0U
    #  define P00_B3 0xFF00FF00FF00FF00U
    #  define P00_B4 0xFFFF0000FFFF0000U
    #  define P00_B5 0xFFFFFFFF00000000U
    #  define P00_B6 0x0U
    # endif /* P00_UNSIGNED_MAX */
    #endif /* P99_UINTMAX_MAX */
    #ifndef P99_UINTMAX_MAX
    # if P00_UNSIGNED_MAX == 0x1FFFFFFFFFFFFFFFF
    #  define P99_UINTMAX_WIDTH 65
    #  define P99_UINTMAX_MAX 0x1FFFFFFFFFFFFFFFFU
    #  define P00_B0 0xAAAAAAAAAAAAAAAAU
    #  define P00_B1 0xCCCCCCCCCCCCCCCCU
    #  define P00_B2 0xF0F0F0F0F0F0F0F0U
    #  define P00_B3 0xFF00FF00FF00FF00U
    #  define P00_B4 0xFFFF0000FFFF0000U
    #  define P00_B5 0xFFFFFFFF00000000U
    #  define P00_B6 0x10000000000000000U
    # endif /* P00_UNSIGNED_MAX */
    #endif /* P99_UINTMAX_MAX */
    .
    .
    .
    
        4
  •  0
  •   Aaron Digulla    14 年前

    是的,因为出于所有实际目的,可能的宽度数量是有限的:

    #if ~0 == 0xFFFF
    # define INT_WIDTH 16
    #elif ~0 == 0xFFFFFFFF
    # define INT_WIDTH 32
    #else
    # define INT_WIDTH 64
    #endif
    
        5
  •  0
  •   Secure    14 年前

    您可以在运行时使用一个简单的循环来计算它,定义良好,不存在ub的危险:

    unsigned int u;
    int c;
    
    for (c=0, u=1; u; c++, u<<=1);
    
    total_bits   = CHAR_BIT * sizeof(unsigned int);
    value_bits   = c;
    padding_bits = total_bits - value_bits;
    

    最简单的方法是检查单元测试 他们,对吧?)该值与当前的int宽度定义相同。

    如果您真的需要在编译时计算它,我将使用给定的一个if-elif级联,或者测试uint-max或者您的目标系统。

    你需要它做什么?也许雅尼?

        6
  •  0
  •   Will    14 年前

    一般的观察是,如果在计算中依赖于数据类型的宽度,则应使用中定义的显式宽度数据类型。 <stdint.h> 例如 uint32_t .

    试图计算标准类型中的字节数是在提出这样一个问题:如果发生溢出,“可移植”代码会做什么。

        7
  •  -1
  •   mouviciel    14 年前

    通常,尺寸为 int 已知的编译器/平台。如果您有标识编译器/平台的宏,那么可以使用它们有条件地定义 INT_WIDTH .

    你可以看看 <sys/types.h> 它的依附性就是一个例子。