【问题标题】:Why does this implicit conversion from int to uint work?为什么这种从 int 到 uint 的隐式转换有效?
【发布时间】:2012-02-18 23:40:57
【问题描述】:

Casting null doesn't compile 为灵感,来自 Eric Lippert 的评论:

这展示了一个有趣的案例。 “uint x = (int)0;”将 即使 int 不能隐式转换为 uint,也会成功。

我们知道这不起作用,因为object 不能分配给string

string x = (object)null;

但这确实如此,虽然直觉上它不应该:

uint x = (int)0;

int 不能隐式转换为uint 时,为什么编译器允许这种情况?

【问题讨论】:

  • 我想unit x = 0 工作的原因相同。 0 是有符号整数,除非您指定 unit x = 0U
  • 可能是 6.1.9 的规范和 int 转换的折扣,因为 0 已经是一个 int。虽然通常 int 不能隐式转换为 uint (6.1.2),但可以转换 int 类型的 常量表达式
  • 那么0 作为常量表达式隐含的值是什么?编译器是否只是忽略(int) 显式转换并将0 视为uint 常量?
  • this Eric Lippert 的回答。
  • @Yuck,编译器看到了一个int 常量。但是,它也知道非负的int 常量可以安全地转换为uint

标签: c# .net compiler-construction type-conversion implicit-conversion


【解决方案1】:

以下代码将失败并显示消息“无法将类型 'int' 隐式转换为 'uint'。存在显式转换(您是否缺少强制转换?)”

int y = 0;
uint x = (int)y;

这将失败:“常量值 '-1' 不能转换为 'uint'”

uint x = (int)-1;

所以uint x = (int)0; 起作用的唯一原因是因为编译器认为 0(或任何其他值 > 0)是一个编译时间常数,可以转换为 uint

【讨论】:

  • 所以基本上它优化了cast away,因为它不需要文字?
  • @BoltClock 可以在编译时转换常量表达式,因此确实删除了强制转换。
【解决方案2】:

整数常量转换被 C# 语言视为非常特殊;这是规范的第 6.1.9 节:

如果常量表达式的值在目标类型的范围内,则可以将 int 类型的常量表达式转换为 sbyte、byte、short、ushort、uint 或 ulong 类型。 long 类型的常量表达式可以转换为 ulong 类型,前提是常量表达式的值不是负数。

这允许您执行以下操作:

byte x = 64;

否则需要一个丑陋的显式转换:

byte x = (byte)64; // gross

【讨论】:

  • @dlev:后者。将 int 类型的常量表达式强制转换为 int 仍然是常量表达式。
  • @gdoron 不,不是。编译器会在编译时知道结果。
  • @JonH:这是一个合理的问题。仅当表达式是 int 类型的常量表达式 并且结果在范围内时,该规则才适用。在这种情况下, (int)0 一个常量表达式。我注意到我们过去在这里犯过错误。例如,规范说 文字零 可以隐式转换为任何枚举。但我们也允许“E e = 0 + 0;”尽管“0 + 0”不是“字面零”——它是两个字面上的零,它们之间有一个加号。
  • @gdoron:它显然不是一个变量,因为一个变量根据定义是一个存储位置。它被归类为一个常量表达式是一种特殊的
  • @CodeInChaos 我认为没有任何数字文字属于byte 类型。对于整数文字,我认为选项是 intuintlongulong,基于可以存储数字的“最小”类型。
【解决方案3】:

一般编译器有 4 个步骤来转换代码。 文本被标记化 > 标记被解析 > 一个 AST 被构建 + 链接 > AST 被转换成目标语言。

对常量(例如数字和字符串)的评估是第一步,编译器可能会将 0 视为有效标记并忽略强制转换。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-05-18
    • 1970-01-01
    • 1970-01-01
    • 2011-12-05
    • 2013-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多