- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
今天以前,我试图添加两个ushort,但我发现必须将结果转换回ushort。我以为它可能已经成为一个uint(以防止可能的意外溢出?),但令我惊讶的是它是一个int(System.Int32)。
是否有一些聪明的原因,或者可能是因为int被视为“基本”整数类型?
例:
ushort a = 1;
ushort b = 2;
ushort c = a + b; // <- "Cannot implicitly convert type 'int' to 'ushort'. An explicit conversion exists (are you missing a cast?)"
uint d = a + b; // <- "Cannot implicitly convert type 'int' to 'uint'. An explicit conversion exists (are you missing a cast?)"
int e = a + b; // <- Works!
最佳答案
简单而正确的答案是“因为C#语言规范是这样说的”。
显然,您对该答案不满意,并且想知道“为什么这么说”。您正在寻找“可信和/或官方来源”,这将有些困难。这些设计决策是在很久以前做出的,在软件工程 Realm 已经有13年的历史了。它们由埃里克·利珀特(Eric Lippert)称呼他们的“老 friend ”制作,他们已经着手做更大更好的事情,因此不在此处发布答案以提供官方消息。
但是,可以推断出它只是可信的风险。任何托管编译器(如C#编译器)都具有这样的约束,即它需要为.NET虚拟机生成代码。 CLI规范中仔细(且易于理解)描述了这些规则。它是Ecma-335的规格,您可以免费下载from here。
转到分区III,第3.1和3.2章。它们描述了可用于执行加法的两条IL指令add
和add.ovf
。单击表2“二进制数值运算”的链接,它描述了那些IL指令允许使用的操作数。请注意,这里仅列出了几种类型。缺少字节和短以及所有无符号类型。仅允许使用int,long,IntPtr和浮点数(float和double)。例如,在用x标记其他约束的情况下,不能将int添加到long中。这些约束并非完全是人为的,它们是基于您可以在可用硬件上合理有效地完成的事情。
任何托管编译器都必须处理此问题才能生成有效的IL。这并不困难,只需将ushort转换为表中较大的值类型,该转换始终有效。 C#编译器选择int,这是表中显示的下一个更大的类型。或通常,将任何操作数转换为下一个最大值类型,以使它们具有相同的类型并满足表中的约束。
但是,现在有了一个新问题,这个问题使C#程序员更加疯狂。添加的结果属于提升类型。在您的情况下,它将为int。因此,将两个ushort值(例如0x9000和0x9000)相加会得到一个完全有效的int结果:0x12000。问题是:这是一个不适合ushort的值。该值溢出。但是它在IL计算中没有溢出,仅在编译器尝试将其填充到ushort中时才溢出。 0x12000被截断为0x2000。令人困惑的不同值,只有在用2或16根手指而不是10根手指计数时才有意义。
值得注意的是,add.ovf指令不处理此问题。这是用于自动生成溢出异常的指令。但事实并非如此,对转换后的int的实际计算并未溢出。
这是真正的设计决策发挥作用的地方。以前的人显然认为,将int结果截断为ushort就是一个错误工厂。必然是。他们决定,您必须承认自己知道添加可能会溢出,并且可以进行添加。他们把它变成了您的问题,主要是因为他们不知道如何使其成为自己的问题,而是仍然生成高效的代码。你必须投。是的,这令人发疯,我敢肯定您也不希望这个问题。
值得注意的是,VB.NET设计人员针对此问题采用了不同的解决方案。他们实际上解决了他们的问题,但并没有因此而失败。您可以添加两个UShorts并将其分配给不带强制转换的UShort。区别在于VB.NET编译器实际上会生成额外的IL以检查溢出条件。那不是便宜的代码,使每次添加的速度慢大约3倍。但是除此之外,这也解释了为什么Microsoft维护两种具有非常相似功能的语言的原因。
长话短说:您付出了代价,因为您使用的类型与现代cpu架构不太匹配。这本身就是使用uint而不是ushort的一个很好的理由。要摆脱ushort的牵引力是困难的,在处理它们的成本超过节省的内存之前,您将需要很多它们。不仅由于CLI规范的限制,x86内核还需要额外的cpu周期来加载16位值,这是因为机器码中的操作数前缀字节。实际上不确定现在是否仍然如此,当我仍然关注计数周期时,它曾经回到过去。一年前的狗。
请注意,通过让C#编译器生成与VB.NET编译器生成的相同的代码,您可以对这些丑陋和危险的转换感到更好。因此,当强制转换被证明是不明智的时,您将获得OverflowException。使用项目>属性>生成选项卡>高级按钮>选中“检查算术上溢/下溢”复选框。仅用于调试版本。为何项目模板没有自动启用此复选框,这是另一个非常神秘的问题,顺便说一下,这个决定是在很久以前做出的。
关于c# - 为什么ushort + ushort等于int?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10065287/
在 .NET Core 上的 C# 中,我正在寻找最快的方法来检查给定的 ushort 是否存在。值存在于 Span 中范围。天真的选项包括枚举跨度,但我强烈怀疑通过 SIMD(即 SSE 或 AVX
在另一个线程中,有人问为什么要添加两个 ushort值在 C# 中引发错误。例如 ushort x = 4; ushort y = 23; ushort z = x+y; // ERROR cann
代码的目的是将两个字节合并为ushort。所有变量都是ushort类型,但M_hi和M_lo加载的是一个字节。我最初将它们作为字节,但发生了这个错误,所以我尝试使用 ushort 第一部分屏蔽了较高的
我收到 VB 错误:“‘Ushort’类型的值无法转换为‘Ushort()’”。 我有一个 VB.NET Windows 应用程序调用 native (C++) DLL 中的函数,以从 DLL 中的页
我有一个非常痛苦的库,目前它正在接受 C# 字符串作为获取数据数组的方式;显然,这使得 pinvoke 的编码更容易。 那么如何把ushort数组按字节转成字符串呢?我试过: int i; Strin
如果我像这样声明一个继承自 ushort 的枚举: public enum MyEnum : ushort { A = 0, B = 1 }; 然后像这样检查它的类型: if(typeof(MyEnu
我在 C 中插入 memcpy() 函数,因为目标应用程序使用它来连接字符串,我想找出正在创建的字符串。代码是: void * my_memcpy ( void * destination, cons
我想知道如何有效地读取和写入特定位到 ushort 整数。 方法应该是这样的: // Sets the bit positioned at bitNumber in the ushort intege
我有一个由两个字节组成的 ushort。 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Y = bits 10-0, twos complement mantissa i
我在 ushort 变量中有一张图片,想以二进制格式保存这张图片。 请任何人告诉我如何使用 C# 完成此操作? 我试过了,但是不行 ushort[] Depthdata; Depthdata = ne
这是我的问题。请容忍我给出一点解释: 我正在将 tiff 图像读入缓冲区;我的 tiff 的每个像素都由一个 ushort 表示(16 位数据,非负数)。 我的图像大小是 64*64 = 4096。当
假设我有一个 ushort 值,我想设置位 1 到 4(假设 0 是 LSB,15 是 MSB)。 在 C++ 中,您可以定义一个映射特定位的结构: struct KibblesNBits {
考虑以下代码: ushort a = 60000; a = (ushort)(a * a / a); Console.WriteLine("A = " + a); //这会打印出 53954。为什么
我有一组 ushort 像素数据,我需要将其保存为 jpeg 文件。根据我的发现,我可以使用 Image.Save(path, ImageFormat.Jpeg); 但我不知道如何将 ushort 数
我知道 byte、unsigned short 和 integer 在内存使用上的区别,但是当涉及到 BufferedImage 时,它们之间是否存在“速度”差异? 我一直在我的代码中使用 Ima
我在为嵌入式平台改编一段代码时遇到了一些麻烦。 eMBFuncReadCoils( UCHAR * pucFrame, USHORT * usLen ) 上面一行是我遇到问题的函数的原型(protot
我有一个 UShort 变量 Temp,它的值为 1。 如何将这个值的最高位设置为1。 最佳答案 您使用 或 覆盖“最左边”的位: ushort temp=1; temp |= 1<<15; 其中 1
这个问题在这里已经有了答案: 10年前关闭。 Possible Duplicate: How do you return 'not uint' in C#? 大家好, 我正在尝试将以下内容从 VB.N
我需要能够将两个 ASCII 字节打包成一个 ushort。我怎样才能做到这一点? 到目前为止我有: for (var i = 0; i > 8); byte b2 = (byte)(x & 255)
我需要对 16 位整数 (ushort/UInt16) 执行按位左移,但 C# 中的按位运算符似乎仅适用于 int(32 位)。我如何在 ushort 上使用 <<,或者至少通过简单的解决方法获得相同
我是一名优秀的程序员,十分优秀!