1

我是一名试图迁移到 C# 的 Java 程序员,这个问题让我有点难过:

int a = 1;

a = 0x08000000 | a;
a = 0x80000000 | a;

第一行编译得很好。第二个没有。似乎认识到有一个带有符号位的常量,并且由于某种原因它决定将结果转换为 long,从而导致错误:

无法将类型“long”隐式转换为“int”。
存在显式转换(您是否缺少演员表?)

到目前为止我的修复是:

a = (int)(0x80000000 | a);

其中涉及演员,但仍然留下警告:

用于符号扩展操作数的位或运算符;
考虑先转换为更小的无符号类型

以错误/警告/无长时间的方式表达这一点的正确 C# 方式是什么?

4

6 回答 6

12

默认情况下,数字整数文字是 an int,除非数字太大而无法放入 anint并且它变为 an (对于and uint,依此类推)。longulong

由于值 0x80000000 太大而无法放入 中int,因此它是一个uint值。当您|在 anint和 an上使用运算符时,uint两者都被扩展为,long因为两者都不能安全地转换为另一个。

该值可以表示为 int,但是您必须忽略它变成负值。编译器不会默默地这样做,所以你必须指示它在int不关心溢出的情况下将值设为 an:

a = unchecked((int)0x80000000) | a;

(注意:这仅指示编译器如何转换该值,因此没有创建用于转换为的代码int。)

于 2010-01-15T14:18:55.057 回答
12

我发现有趣的是,在所有这些答案中,实际上只有一个人建议按照警告所说的去做。警告告诉您如何解决问题;注意它。

用于符号扩展操作数的位或运算符;考虑先转换为更小的无符号类型

按位或运算符用于符号扩展的操作数:int。这导致结果被转换为更大的类型:long。小于 long 的无符号类型是 uint。所以按照警告说的去做;将符号扩展的操作数 - int - 强制转换为 uint:

result = (int)(0x80000000 | (uint) operand);

现在没有符号扩展。

当然,这只是提出了一个更大的问题:为什么首先将有符号整数视为位域?这似乎是一件危险的事情。

于 2010-01-15T15:43:07.407 回答
1

您的问题是因为 0x80000000 是 int 形式的减号,您不能对减号执行按位运算。

如果您使用 uint,它应该可以正常工作。

a = ((uint)0x80000000) | a;  //assuming a is a uint
于 2010-01-15T14:09:59.330 回答
1

改变那条线
(int)((uint)0x80000000 | (uint)a);
为我做这件事。

于 2010-01-15T14:15:47.360 回答
0

你在这里遇到的问题是

  • 0x80000000是一个无符号整数文字。规范说整数文字是列表中的第一种类型(int, uint, long, ulong),它可以保存文字。在这种情况下,它是uint
  • a可能是一个int

这会导致结果long. 除了将结果转换回之外,我没有看到更好的方法int,除非您知道这a不能是负数。然后,您可以首先以这种方式强制a转换uint或声明它。

于 2010-01-15T14:21:32.323 回答
0

您可以通过创建一个以字母“O”开头的常量来使其不那么难看。(与此网站不同,在视觉工作室中,它不会以不同的颜色显示)。

const int Ox80000000 = unchecked((int)0x80000000);

/// ...

const int every /*  */ = Ox80000000;
const int thing /*  */ = 0x40000000;
const int lines /*  */ = 0x20000000;
const int up /*     */ = 0x10000000;
于 2012-07-30T02:20:02.990 回答