C转换有符号到无符号,保持精确位 > >编辑:我更新了例子是C。我特别关注C而不是C++(抱歉混淆了,请参阅下面的情况)。

C转换有符号到无符号,保持精确位 > >编辑:我更新了例子是C。我特别关注C而不是C++(抱歉混淆了,请参阅下面的情况)。,c,type-conversion,C,Type Conversion,我正在寻找一种将有符号整数转换为无符号整数的安全方法,同时在转换之间始终保持完全相同的位模式。据我所知,简单转换具有未定义或依赖于实现的行为,因此依赖它是不安全的(下面的案例A)。但是像OR这样的位运算符呢(下面的情况B)?按位或可以用于安全地将有符号转换为无符号吗?反面呢 例如: #include <stdio.h> int main() { // NOTE: assuming 32bit ints // example bit pattern: 11111111

我正在寻找一种将有符号整数转换为无符号整数的安全方法,同时在转换之间始终保持完全相同的位模式。据我所知,简单转换具有未定义或依赖于实现的行为,因此依赖它是不安全的(下面的案例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);
}
#包括
int main(){
//注:假设32位整数
//示例位模式:1111111 0001100010011111011010
//符号整数值:-3730470
//无符号整数值:4291236826
//例1
//已签名->未签名
int s1=-3730470;
无符号整数u1a=(无符号整数)s1;
无符号整数u1b=(无符号整数)0 | s1;
printf(“%u\n%u\n”,u1a,u1b);
//例2
//未签名->已签名
无符号整数u2=4291236826;
int s2a=(int)u2;
int s2b=(int)0 | u2;
printf(“%i\n%i\n”,s2a,s2b);
}

情况:我正在编写一个/扩展来添加popcount功能()。PostgreSQL不支持无符号类型()。我发现的所有计算popcount的有效方法都需要无符号数据类型才能正常工作。因此,我必须能够在不更改位模式的情况下将有符号数据类型转换为无符号数据类型

离题:我确实意识到另一种解决方案是使用PostgreSQL位字符串
bit
varbit
数据类型,而不是整数数据类型,但就我而言,整数数据类型更易于使用和管理

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

即使
int
是罕见的非2的补码,
union
也将按如下方式工作。只有在非常令人期待的平台上(在硅墓地中滴答作响),如果
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)?
按位或可以用于安全地将有符号转换为无符号吗

以下
|
类似于整数升级的隐藏模式:

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


反面呢

如果值在
[0…int\u MAX]
中都可以表示,则将
无符号整数
转换为
有符号整数
是很好的定义。将超出范围的
int
无符号
转换为
int

要么结果是实现定义的,要么引发实现定义的信号。§6.3.1.3 3

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

// NOTE: assuming 32bit ints, etc.
unsigned int u2 = 4291236826;
int s2a = (int)u2;  // avoid this
另类

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

顺便说一句:最好将
u
附加到像4291236826这样的无符号常量上,以便向编译器传达一个无符号常量实际上是有意使用的,而不是像4291236826这样的
long

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

即使
int
是罕见的非2的补码,
union
也将按如下方式工作。只有在非常令人期待的平台上(在硅墓地中滴答作响),如果
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)?
按位或可以用于安全地将有符号转换为无符号吗

以下
|
类似于整数升级的隐藏模式:

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


反面呢

如果值在
[0…int\u MAX]
中都可以表示,则将
无符号整数
转换为
有符号整数
是很好的定义。将超出范围的
int
无符号
转换为
int

要么结果是实现定义的,要么引发实现定义的信号。§6.3.1.3 3

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

// NOTE: assuming 32bit ints, etc.
unsigned int u2 = 4291236826;
int s2a = (int)u2;  // avoid this
另类

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

顺便说一句:最好将
u
附加到像4291236826这样的无符号常量上,以便向编译器传达一个无符号常量实际上是有意使用的,而不是像4291236826这样的
long

unsigned int u2 = 4291236826u;
那么

int s1 = -3730470; 
unsigned int u1 = *(unsigned int*)&s1;

unsigned int u2 = 4291236826;
int s2a = *(int*)&u2;
那么

int s1 = -3730470; 
unsigned int u1 = *(unsigned int*)&s1;

unsigned int u2 = 4291236826;
int s2a = *(int*)&u2;

使用
联合
来保持精确位。“简单的铸造有未定义或依赖于实现的行为,所以依赖于它是不安全的”“不是要去代码>未签名< /Code >。代码看起来是C++,但是问题被标记为C…记住符号位表示是实现定义的。所以很明显,它在不同的平台上会有不同的行为。为了补充EugeneSh所说的,如果您试图进行位(屏蔽)操作,请使用unsigned。如果您混合使用有符号和无符号,那么您可能正在尝试对算术相关代码进行低级位操作(为什么?),或者有人正在这样做