C将signed转换为unsigned维护精确位

时间:2017-07-06 16:18:09

标签: c type-conversion

编辑:我将示例更新为C.我特别关注C而不是C ++(抱歉混淆,请参阅下面的情况)。

我正在寻找一种将有符号整数转换为无符号整数的安全方法,同时始终在转换之间保持完全相同的位模式。据我所知,简单的转换具有未定义或依赖于实现的行为,因此依赖它是不安全的(下面的情况A)。但是像OR这样的位运算符呢(下面的情况B)?可以按位或用于安全地将签名转换为无符号吗?反过来呢?

示例:

#include <stdio.h>

int main() {
    // NOTE: assuming 32bit ints
    // example bit pattern: 11111111110001110001001111011010
    //   signed int value: -3730470
    // unsigned int value: 4291236826

    // example 1
    // signed -> unsigned
    int s1 = -3730470; 
    unsigned int u1a = (unsigned int)s1;
    unsigned int u1b = (unsigned int)0 | s1;

    printf("%u\n%u\n", u1a, u1b);

    // example 2
    // unsigned -> signed
    unsigned int u2 = 4291236826;
    int s2a = (int)u2;
    int s2b = (int)0 | u2;

    printf("%i\n%i\n", s2a, s2b);
}

情况:我正在编写PostgreSQL C-Language function /扩展名以添加popcount功能(my first attempt code here)。 PostgreSQL不支持无符号类型(ref)。计算popcount的所有有效方法都需要无符号数据类型才能正常工作。因此,我必须能够将签名数据类型转换为无符号数据类型而不更改位模式。

非主题:我确实认识到另一种解决方案是使用PostgreSQL位字符串bitvarbit数据类型而不是整数数据类型,但对于我的目的,整数数据类型更容易使用和管理。

2 个答案:

答案 0 :(得分:2)

  

将有符号整数转换为无符号整数的安全方法,同时始终在转换之间保持完全相同的位模式

即使union是罕见的非2补码,int也会如下工作。只有在非常期待的平台上(在硅墓地中嘀嗒一声)INT_MAX == UINT_MAX这将是一个问题。

union {
  int i;
  unsigned u;
} x = { some_int };
printf("%d\n", some_int);
printf("%u\n", x.u);

然而,如果一个人可以将自己限制在共同的2的补语int,那么下面就足够了。

unsigned u = (unsigned) some_int;
  

但是像OR这样的位运算符呢(下面的情况B)?   可以按比特使用OR来安全地将signed转换为unsigned吗?

由于整数促销,以下|就像一个隐藏的演员:

  

如果int可以表示原始类型的所有值(受宽度限制,对于位字段),则该值将转换为int;否则,它将转换为unsigned int。 C11dr§6.3.1.13

int s1 = -3730470; 
unsigned int u1b = (unsigned int)0 | s1;
// just like
                 = (unsigned int)0 | (unsigned int)s1;
                 =                   (unsigned int)s1;
  

反过来呢?

如果unsigned int中的值可以表示,则可以很好地定义signed int[0...INT_MAX]。将int范围unsigned范围int转换为// NOTE: assuming 32bit ints, etc. unsigned int u2 = 4291236826; int s2a = (int)u2; // avoid this 是......

  

结果是实现定义的,或者引发实现定义的信号。 §6.3.1.33

最好使用无符号类型进行位操作 以下代码通常可以按预期工作,但不应用于强大的编码。

int s2a;
if (u2 > INT_MAX) {
  // Handle with some other code
} else {
  s2a = (int) u2; // OK
}

替代

u

BTW:最好将long long附加到无符号常量,如4291236826,以便向编译器传达确实无符号常量而不是{{1像4291236826。

unsigned int u2 = 4291236826u;

答案 1 :(得分:0)

那......

| USID |                 Date | Utilized | RowNumber |
|------|----------------------|----------|-----------|
|  123 | 2019-01-01T00:00:00Z |        T |         1 |
|  123 | 2019-01-02T00:00:00Z |        T |         2 |
|  123 | 2019-01-03T00:00:00Z |        T |         3 |
|  123 | 2019-01-04T00:00:00Z |        F |         1 |
|  123 | 2019-01-05T00:00:00Z |        F |         2 |
|  123 | 2019-01-06T00:00:00Z |        F |         3 |
|  123 | 2019-01-07T00:00:00Z |        F |         4 |
|  123 | 2019-01-08T00:00:00Z |        F |         5 |
|  123 | 2019-01-09T00:00:00Z |        F |         6 |
|  123 | 2019-01-19T00:00:00Z |        T |         1 |
|  123 | 2019-01-20T00:00:00Z |        T |         2 |
|  123 | 2019-01-21T00:00:00Z |        T |         3 |
|  223 | 2019-01-01T00:00:00Z |        T |         1 |
|  223 | 2019-01-02T00:00:00Z |        T |         2 |
|  223 | 2019-01-03T00:00:00Z |        T |         3 |
|  223 | 2019-01-04T00:00:00Z |        F |         1 |
|  223 | 2019-01-05T00:00:00Z |        F |         2 |
|  223 | 2019-01-06T00:00:00Z |        F |         3 |
|  223 | 2019-01-07T00:00:00Z |        F |         4 |
|  223 | 2019-01-08T00:00:00Z |        F |         5 |
|  223 | 2019-01-09T00:00:00Z |        F |         6 |
|  223 | 2019-01-19T00:00:00Z |        T |         1 |
|  223 | 2019-01-20T00:00:00Z |        T |         2 |
|  223 | 2019-01-21T00:00:00Z |        T |         3 |