如何检查值是否适合类型?

时间:2014-03-03 21:33:51

标签: c types overflow

假设我有一个名为T的类型名称,其大小始终为>= T2,两者都是无符号的。如何检查a类型的变量T是否适合T2而没有溢出,如果它不适合做其他操作?我已经尝试检查它是否变为负面,但我不确定这是否是正确的检查方式,如下所示:

T a = ...;
T2 b = a;
if(b < 0) // didn't fit
else // ok, fit

4 个答案:

答案 0 :(得分:1)

这不会奏效:如果TT2未签名,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 underflowIs 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;
}