假设我有一个名为T
的类型名称,其大小始终为>=
T2
,两者都是无符号的。如何检查a
类型的变量T
是否适合T2
而没有溢出,如果它不适合做其他操作?我已经尝试检查它是否变为负面,但我不确定这是否是正确的检查方式,如下所示:
T a = ...;
T2 b = a;
if(b < 0) // didn't fit
else // ok, fit
答案 0 :(得分:1)
这不会奏效:如果T
和T2
未签名,b < 0
将始终为假。
由于这两种类型都是无符号的,因此保证溢出会导致回绕(旁注:如果这些是带符号的类型,溢出会导致UB,尽管通常也会包围)。因此,您可以使用以下内容:
T a = ...;
T2 b = a;
if ((T) b != a) {
/* didn't fit */
}
else { ... }
b
周围的演员表并非绝对必要:如果sizeof(T)
&gt; sizeof(T2)
,然后通常的算术转换会导致b
在与T
比较之前转换为a
。但是,为了说清楚,我选择明确地将它留在那里。
根据C99第6.3.1.3节(见下面的评论),当无符号整数转换为更窄的无符号类型时会发生这种情况:
如果新类型是无符号的,则重复转换该值 加或减一个可能的最大值 以新类型表示,直到值在新范围内 型
这意味着如果发生溢出,b
在转换回a
时将不等于T
。这是该代码背后的基本原理。此外,它会少而不是a
,因此如果您愿意,可以将!=
切换为<
。
或者,您可以在分配到b
之前进行检查以确保其适合:
T a = ...;
T2 b;
if (a > (T2)-1) {
/* won't fit */
}
else {
/* fits */
}
(T2) -1
是无符号类型T2
可以容纳的最大值。如果a
大于此值,那么它显然不适合b
。要了解(T2) -1
可移植且始终有效的原因,请参阅此问题:Is it safe to use -1 to set all bits to true?
答案 1 :(得分:0)
T a = ...;
T2 b = a;
if (b < a) // didn't fit
else // ok, fit
离你写的只有一个字节: - )
这是有效的,因为对于无符号类型,溢出始终会生成较小的值,而比较只会将b
转换为T
,这是没有问题的。
来自C99标准( 6.3.1.3有符号和无符号整数):
[...]如果新类型是无符号的,则值为 通过重复加或减一个转换而来 在值之前可以在新类型中表示的最大值 在新类型的范围内。
这也意味着Joseph Quinsey的解决方案是正确的:您始终可以将a
与(T2)-1
进行比较,保证这是无符号类型T2
可以容纳的最大值:
if (a > (T2)-1)) // won't fit
请注意,标准从不谈论“尺寸”(除非在谈论sizeof
时),以保持一般性。当然,我引用的迭代过程归结为可能在所有当代架构中截断高阶位,但你永远不知道......
答案 2 :(得分:0)
由于T2
未签名,因此if (b < 0)
将不工作。以下应该没问题:
T a = ...;
T2 b;
if (a > (T2)-1) // a won't fit into a T2
//...
else
b = a; // safe, no overflow, value unchanged
您需要-1
而不是~0
,因为后者是int
,如果T2
宽于int
,则无效。 (但~0LL
适用于所有常用类型。)
我认为对于无符号类型T2
,其最大值始终为(T2)-1
。从C99标准:
6.3.1.3有符号和无符号整数
1当整数类型的值转换为_Bool以外的另一个整数类型时,if 该值可以用新类型表示,不变。
2否则,如果新类型是无符号的,则通过重复添加或转换该值 减去一个可以在新类型中表示的最大值 直到该值在新类型的范围内。 49)
3否则,新类型已签名且值无法在其中表示;无论是 结果是实现定义的或引发实现定义的信号。
因此,例如,如果T2
的最大值为10
,那么(T2)-1
会通过将11
添加到-1
进行评估,以获得{ {1}},视情况而定。
另请参阅Question about C behaviour for unsigned integer underflow和Is it safe to assign -1 to an unsigned int to get the max value?以及Signed to unsigned conversion in C - is it always safe?。
答案 3 :(得分:-1)
我在这里放了一些伪代码来帮忙。您应该能够通过整理来从该伪代码中获得答案。
您要做的是检查所有&gt;的位。 T2中的位数。如果其中任何一个为“1”,则无法将该特定T变量安全地存储在T2中。
// If T is an int (32 bits) and T2 is a char (8 bits):
// assume variable a is the integer in question.
int mask = 0;
for (int i = sizeof(T2); i < sizeof(T); ++i)
{
int mask = 1 << i;
if (a & mask)
{
// if this hits, we have a "1" in that bit, so the value cannot fit.
return false;
}
return true;
}