位掩码和长长整型

5
我有一个掩码程序(为给定大小的底部创建全1位掩码):
template<class T>
T bottom_half() {
    T halfway = ((sizeof(T) * 8) / 2);
    T mask = (1 << halfway) - 1;

    return mask;
}

如果我调用 bottom_half<int>() 或者 long 或者 char,它可以正常工作。但是当我使用 long long 运行时,halfway 被正确设置为 32,但是 mask0。这是为什么?

2
一个整数一半的正确拼写是 std::numeric_limits<T>::digits / 2。上面使用的表达式假设 char 有8位,这是必需的(尽管我不知道任何平台不是8位)。 - Dietmar Kühl
啊,知道了,谢谢。 - sircodesalot
@Nawaz:是的,char不需要恰好有8位。它至少有8位。我听说过唯一一个拥有超过8位char的平台是一些Cray,据说它们有64位的char - Dietmar Kühl
@MarkLakata:不是真的,根据18.3.2.4 [numeric.limits.members]第8段:“static constexpr int digits; 可以表示而不改变的radix数字的数量。” 3.9.1 [basic.fundamental]第7段规定:“...整数类型的表示应使用纯二进制计数系统定义值...” 我认为这相当于内置整数类型的基数为2。十进制数字的数量由std::numeric_limits<T>::digits10给出。 - Dietmar Kühl
@DietmarKühl - 抱歉,您是正确的。 - Mark Lakata
显示剩余5条评论
3个回答

8
左移是将默认情况下为32位的int向左移动1位。当你将1<<32进行移位时,结果是未定义的,这意味着它不再可预测,因为它可能是任何值。
在某些处理器上,1<<32可能导致将位移出整数的高端并导致为0。在其他处理器上,32位移相当于对寄存器大小取模,因此有效地是零移位,结果为1。无论哪种情况,都是未定义的。
(有关此问题的讨论,请参见What's bad about shifting a 32-bit variable 32 bits?)。
还要注意,sizeof返回单位char或“字节”(在C中定义为相同的,sizeof(char) == 1始终成立),但C不保证一个字节是8位。有一个标准宏CHAR_BIT可以获取char的位大小。
请尝试此操作。
#include <limits.h>

template<class T>
T bottom_half() {
    T halfway = ((sizeof(T) * CHAR_BIT) / 2);
    T mask = ((T)1 << halfway) - 1;

    return mask;
}

那么你的意思是(1 << 32) - 1就是0吗? - Nawaz
@dasblinkenlight:具体怎么做? - Nawaz
1
@Nawaz:如果int有32位或更少,则表达式1 << 32具有未定义的行为。 - Dietmar Kühl
@dasblinkenlight:是的,那是正确的,但这个答案没有涉及到未定义行为(UB),这就是我提出这个问题的原因。 - Nawaz
@MarkLakata:是的,如果不是错误的话,你的回答是误导性的。如果你明白其中的问题,请纠正它。 - Nawaz

3

1 << x表达式的类型为int。如果对有符号类型进行左移操作,值超过了最大可表示的值,则行为未定义。建议使用T(1) << x


+1。这是目前为止的正确答案,因为它还涉及到原始代码中的“未定义行为”。 - Nawaz

0
将您位移操作中的1转换为正确的类型。目前它只是一个简单的整数,因此位移不起作用--您会将该位移位移出存在。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接