算术右移 size_t 值

Arithmetic right-shift a size_t value

size_t类型是无符号类型。因此,右移 size_t 类型的值将逻辑移位。鉴于 size_t 的宽度取决于实现,是否有任何方法可以算术右移 size_t 值?

如果我的目标是从包含 10size_t 值创建位掩码,还有其他方法吗?对于宽度已知的整数,我知道制作位掩码的最简单方法是左移整数的宽度 - 1,然后算术右移一直返回。

这适用于我的 64 位系统:

const size_t width = (sizeof(size_t) << 3)) - 1;
size_t value = {boolean value};
value = ((int64_t) (value << width)) >> width;

但当然它特定于我的系统和类似的系统。我可以用什么代替?

尝试这样的事情:

#define UNSIGNED_SRA(x,n) ((x)<=(0?(x):-1)/2 ? (x)>>(n) : ~(~(x)>>(n)))

表达式(0?(x):-1)/2求得x类型的最大值,高位清零;如果你知道一个特定的类型,比如 size_t,你可以只使用 SIZE_MAX/2.

对于具有算术右移操作码的机器的任何良好的优化编译器都应该认识到这两个分支对于它们处理的情况是相同的,并且完全优化分支,产生单个无分支操作。

您的原始代码……

const size_t width = (sizeof(size_t) << 3)) - 1;
size_t inpvalue = {zero or one};
size_t outvalue = ((int64_t) (value << width)) >> width;

...可以这样简化:

size_t inpvalue = {zero or one};
size_t outvalue = -inpvalue;

Is there any way to right-shift a size_t value arithmetically?

是的,有。事实上,给定一个无符号类型的值 v,我相信你可以按如下方式执行算术右移(size_t 的示例):

v = (v >> 1U) | (v & ~(~(size_t) 0 >> 1U));

基本上,它执行逻辑右移,然后如果移位前的最高有效位为 1,则将最高有效位设置为 1。

这是一个小玩具程序,用于 运行 一些测试:

#include <stdio.h>

void print_binary(size_t v) {
    size_t mask = ~(~(size_t) 0 >> 1U);
    while (mask) {
        putchar('0'+!!(v&mask));
        mask >>= 1U;
    }
    putchar('\n');
}

int main() {
    size_t v;

    // Some random number
    v = 5583705;
    print_binary(v);
    v = (v >> 1U) | (v & ~(~(size_t) 0 >> 1U));
    print_binary(v);

    v = ~(~(size_t) 0 >> 1U);
    print_binary(v);
    int i;
    for (i = 0; i < 10; i++) {
        v = (v >> 1U) | (v & ~(~(size_t) 0 >> 1U));
        print_binary(v);
    }   

    return 0;
}

在我的机器上,打印出:

0000000000000000000000000000000000000000010101010011001101011001
0000000000000000000000000000000000000000001010101001100110101100
1000000000000000000000000000000000000000000000000000000000000000
1100000000000000000000000000000000000000000000000000000000000000
1110000000000000000000000000000000000000000000000000000000000000
1111000000000000000000000000000000000000000000000000000000000000
1111100000000000000000000000000000000000000000000000000000000000
1111110000000000000000000000000000000000000000000000000000000000
1111111000000000000000000000000000000000000000000000000000000000
1111111100000000000000000000000000000000000000000000000000000000
1111111110000000000000000000000000000000000000000000000000000000
1111111111000000000000000000000000000000000000000000000000000000
1111111111100000000000000000000000000000000000000000000000000000

似乎工作正常。

对于你的具体问题,我相信 dlask 的答案是这里最好的方法,但我决定 post 这个答案,因为你表现出有兴趣知道如何(以及是否)可以进行算术右移在无符号类型上。