有人可以帮忙解释这个C one liner的作用吗?

时间:2010-08-02 03:40:49

标签: c

我通常可以找出大多数C代码,但这个代码已经超出了我的想法。

#define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))

示例用法如下:

int x = 57;
kroundup32(x);
//x is now 64

其他一些例子是:

1到1
2至2
7至8
31至32
60至64
3000至4096

我知道这是将整数四舍五入到它最近的2的幂,但就我的知识来说,这就差不多了。

非常感谢任何解释。

由于

3 个答案:

答案 0 :(得分:20)

(--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
  1. 将x减少1
  2. OR x with(x / 2)。
  3. OR x with(x / 4)。
  4. OR x with(x / 16)。
  5. OR x with(x / 256)。
  6. OR x with(x / 65536)。
  7. 将x增加1。
  8. 对于32位无符号整数,这应该将值移动到等于或大于2的最接近幂。 OR部分将所有低位设置为最高位以下,因此它最终为2减去1的幂,然后再添加一个。它看起来有点优化,因此不太可读;通过按位运算和单独位移,以及作为宏(因此没有函数调用开销)来完成它。

答案 1 :(得分:6)

按位或移位操作实质上设置了最高设置位和位0之间的每一位。这将生成一些2^n - 1形式。最后的增量增加一个以获得2^n形式的数字。初始减量可确保您不会将已经为2的幂的数字舍入到下一个幂,以便例如2048年不会成为4096。

答案 2 :(得分:6)

在我的机器kroundup32给出6.000米回合/秒
下一个函数给出7.693m回合/秒

inline int scan_msb(int x)
{
#if defined(__i386__) || defined(__x86_64__)
    int y;
    __asm__("bsr %1, %0"
            : "=r" (y)
            : "r" (x)
            : "flags"); /* ZF */
    return y;
#else
#error "Implement me for your platform"
#endif
}

inline int roundup32(int x)
{
    if (x == 0) return x;
    else {
        const int bit = scan_msb(x);
        const int mask = ~((~0) << bit);
        if (x & mask) return (1 << (bit+1));
        else return (1 << bit);
    }
}

所以@thomasrutter我不是说它是“高度优化的”。

适当(仅有意义的部分)装配(适用于GCC 4.4.4):

kroundup32:
    subl    $1, %edi
    movl    %edi, %eax
    sarl    %eax
    orl %edi, %eax
    movl    %eax, %edx
    sarl    $2, %edx
    orl %eax, %edx
    movl    %edx, %eax
    sarl    $4, %eax
    orl %edx, %eax
    movl    %eax, %edx
    sarl    $8, %edx
    orl %eax, %edx
    movl    %edx, %eax
    sarl    $16, %eax
    orl %edx, %eax
    addl    $1, %eax
    ret

roundup32:
    testl   %edi, %edi
    movl    %edi, %eax
    je  .L6
    movl    $-1, %edx
    bsr %edi, %ecx
    sall    %cl, %edx
    notl    %edx
    testl   %edi, %edx
    jne .L10
    movl    $1, %eax
    sall    %cl, %eax
.L6:
    rep
    ret
.L10:
    addl    $1, %ecx
    movl    $1, %eax
    sall    %cl, %eax
    ret

由于某些原因,我未在GCC的标准标题中找到scan_msb(如#define scan_msb(x) if (__builtin_constant_p (x)) ...)的适当实现(仅__TBB_machine_lg/__TBB_Log2)。