【问题标题】:Why does C# issue the error "cannot implicitly convert int to ushort" against modulo arithmetic on ushorts?为什么 C# 会针对 ushorts 上的模运算发出错误“无法将 int 隐式转换为 ushort”?
【发布时间】:2019-04-11 17:52:32
【问题描述】:

在另一个线程中,有人问为什么在 C# 中添加两个 ushort 值会引发错误。例如

ushort x = 4;
ushort y = 23;
ushort z = x+y;  // ERROR cannot implicitly convert int to ushort 

在该线程上,人们认为加号 + 运算符默认采用两个整数,这是一种有助于避免算术溢出的语言功能。但是我在以下函数中遇到了同样的错误:

public RGB(ushort red, ushort green, ushort blue)
{
    // this class RGB has three ushort fields: r, g, and b
    r = red % ((ushort)256);
    g = green % ((ushort)256);
    b = blue % ((ushort)256);
}

编译器出错并显示“无法将类型 'int' 隐式转换为 'ushort'。存在显式转换...”。但是在这里,模 % 运算符防止溢出的论点根本没有任何意义:如果 x 和 y 是 ushort 值,则 x%y < max(x,y),因此没有溢出到整数的风险。那么为什么会出现这个错误呢?

【问题讨论】:

    标签: c# integer-overflow


    【解决方案1】:

    正在使用的 % 运算符,即使是 shortsushorts,也具有 int %(int a, int b) 的签名。所以你的短裤被提升为整数,你的结果是一个你试图分配给ushort的整数,这是一个有损转换,所以你需要明确。

    考虑一下:

    ushort x = 5;
    ushort y = 6;
    var res = x % y;
    Console.WriteLine(res.GetType()); // System.Int32
    ushort z = res; // cast error, explicit conversion exists
    ushort zz = (ushort)res; // Fine, we cast down.
    

    【讨论】:

    • 哦,当然,我认为签名正在提升它,但我不明白 为什么 有那个签名。为什么不重载并拥有多个签名,例如 ushort %(ushort a, ushort b)int %(int a, int b)long %(long a, long b)ulong %(ulong a, ulong b)
    • @GregoryFenn:正如我在另一条评论中指出的那样,语言设计者不需要说明他们没有做某事的原因。几乎没有人对 ushorts 进行算术运算;它们几乎只是为了与非托管代码兼容而存在。证明一个特性为什么应该存在的责任在于想要这个特性的人;我不必给你一个我没有做你想做的事的理由;你必须给我一个理由!
    • 好吧,原因在我的 OP 中已经说明了,也许在字里行间有点:但没关系。您应该实现 ushort %(ushort a, ushort b) 是有效签名的功能,因为在数学上不可能通过模将 ushort 溢出到 int 中。
    • @GregoryFenn 编译器是开源的,你可以考虑设计它。我不确定防止溢出是没有实现这些类型的运算符的原因,显然int +(int a, int b) 运算符在将两个大整数相加时没有任何作用来防止溢出。
    【解决方案2】:

    这是因为没有为小于int 的整数类型定义% 运算符。 C# 规范列出了为整数类型的模运算符定义的所有重载:

    int operator %(int x, int y);
    uint operator %(uint x, uint y);
    long operator %(long x, long y);
    ulong operator %(ulong x, ulong y);
    

    https://github.com/dotnet/csharplang/blob/master/spec/expressions.md#remainder-operator

    在 ushorts 上使用 %,然后默认使用上面列表中的第一个重载,它返回一个不能隐式转换为 ushortint


    如果你问为什么它没有被定义,你可能不得不问 C# 规范的创建者。

    【讨论】:

    • 我宁愿你不要问我们“为什么不”的问题;语言设计者不需要给出他们没有做某事的原因!相反,如果您认为缺少某项功能,您需要提供其存在的理由。
    • 我的意思是,我确实多次使用了“为什么”这个词。如果您不回答这个问题,那没关系,但我的帖子已经认识到 % 是返回 ushort 的无效运算符(除了通过额外的转换),我在问这是什么逻辑。就像我说的那样,在另一个线程中,人们认为这是为了避免溢出,这是公认的答案,但如果他们要保持一致,那么这里就不适用了。没有人说问为什么“ushort +(ushort, ushort) 无效”是一个无效的问题,所以同样的道理,没有人应该有权对我说同样的话。
    猜你喜欢
    • 1970-01-01
    • 2013-09-18
    • 1970-01-01
    • 2015-04-12
    • 1970-01-01
    • 2017-12-21
    • 2017-02-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多