【问题标题】:Why some types do not have literal modifiers为什么有些类型没有文字修饰符
【发布时间】:2012-01-30 01:58:06
【问题描述】:

例如,为什么 long int 有文字修饰符,而 short int 没有?我指的是这个网站上的以下问题:C# compiler number literals

总的来说,C# 似乎是一种设计良好且一致的语言。可能有充分的理由为某些类型提供文字修饰符,但不是全部。这是什么?

【问题讨论】:

标签: c# literals


【解决方案1】:

为什么 long int 有文字修饰符,而 short int 没有?

问题是“为什么 C# 没有这个特性?”这个问题的答案总是一样的。功能默认未实现; C# 没有该功能,因为没有人设计、实现并将该功能交付给客户。

缺少某项功能不需要理由。相反,所有功能都必须通过证明其收益大于成本来证明其合理性。作为提出该功能的人,您有责任描述您认为该功能有价值的原因;我没有责任解释为什么不这样做。

可能有充分的理由为某些类型提供文字修饰符,但不是全部。这是什么?

现在这是一个更容易回答的问题。现在的问题是“是什么证明了 long 上的文字后缀是合理的,为什么这也不是 short 上类似文字后缀的证明?”

整数可用于多种用途。您可以将它们用作算术数字。您可以将它们用作位标志的集合。您可以将它们用作数组的索引。还有很多特殊用途的用法。但我认为公平地说,大多数时候,整数被用作算术数字。

普通程序以整数执行的绝大多数计算涉及的数字远远小于 32 位有符号整数的范围——大约 +/- 20 亿。许多现代硬件在仅处理 32 位整数时非常高效。因此,将数字的默认表示设为有符号 32 位整数是有意义的。因此,C# 旨在使涉及 32 位有符号整数的计算看起来非常正常;当你说“x = x + 1”时,“1”被理解为一个有符号的 32 位整数,并且 x 也是如此,并且总和的结果也是如此。

如果计算是整数但不适合 32 位整数的范围怎么办? “长” 64 位整数是明智的下一步;它们在许多硬件上也很有效,并且 longs 的范围应该可以满足几乎所有不从事涉及大量数字的重型组合的人的需求。因此,有一些方法可以在源代码中清晰简洁地指定此处的文字将被视为长整数。

互操作场景,或将整数用作位字段的场景,通常需要使用无符号整数。同样,有一种方法可以清楚而简洁地指定此文字旨在被视为无符号整数。

因此,总而言之,当您看到“1”时,绝大多数情况下用户希望将其用作 32 位有符号整数的可能性很大。下一个最可能的情况是用户希望它是长整数或无符号整数或无符号长整数。因此,每种情况都有简洁的后缀。

因此,该功能是合理的。

为什么这不是短裤的理由?

因为首先,在任何一个short 是合法的上下文中,使用一个整数字面量已经是合法的了。 "short x = 1;"完全合法;编译器意识到整数适合短并允许您使用它。

其次,算术永远不会在 C# 中完成。算术可以用 int、uint、long 和 ulong 来完成,但算术从不用 short 来完成。 Shorts 提升为 int 并且算术是在 int 中完成的,因为就像我之前所说的,绝大多数算术计算都适合 int。绝大多数人适合短片。在为整数优化的现代硬件上,短算术可能更慢,而且短算术不会占用更少的空间;它将在芯片上以整数或长整数形式完成。

您想要一个“长”后缀来告诉编译器“这个算术需要以长整数来完成”,但一个“短”后缀不会告诉编译器“这个算术需要在短时完成”,因为那根本不是C# 语言的一个特性。

提供长后缀和无符号语法的原因不适用于短裤。如果您认为该功能具有令人信服的好处,请说明好处是什么。如果没有证明其成本合理的好处,该功能将不会在 C# 中实现。

【讨论】:

  • 一致性应该是一个足够强大的理由,不是吗?但是,这种不一致似乎是有原因的:每次我需要对我的 short 做任何事情时,它都会警告我转换为 int 并返回到 short 的成本。
  • @Lund:转换几乎没有任何成本,除非使用检查算法。算术是在 CPU 寄存器中完成的,这些寄存器总是至少 32 位宽。内存加载和存储指令实际上会进行转换,它们的周期数可能略有不同。但是,更好的缓存利用率通常足以弥补任何损失,这可能会使使用 short 的整体性能比使用 int 更好。
  • @KevinCathcart:当然前提是短裤包装得很紧。例如,一个 short 数组可能导致比 int 数组更少的缓存未命中。但是我经常看到有人将局部变量声明为短,因为他们认为这样做是“节省了两个字节的内存”,这是无稽之谈。
【解决方案2】:

根据MSDN

short x = 32767;

在前面的声明中,整数文字 32767 是隐式的 从 int 转换为 short。如果整数文字不适合 存储位置短,会出现编译错误。

所以它是一个编译时特性。 short 没有后缀,因为它永远不需要。

相关的问题可能是:为什么longfloatdecimal 有后缀?
一个简短的回答是i + 1i + 1L 可以产生不同的值,因此属于不同的类型。

但不存在“短算术”之类的东西,short 值在用于计算时总是转换为int

【讨论】:

  • Henk,我喜欢你的文章。很遗憾我不能接受两个答案。
【解决方案3】:

正如埃里克在评论中指出的那样,我在下面的回答没有意义。我认为更正确的说法是无法在 C# 中表达短文字和无法在 IL 中表达短文字有一个共同的原因(该功能缺乏令人信服的理由。)VB.Net 显然有一个短文字说明符,这很有趣(为了向后兼容 VB 语法?)无论如何,我在这里留下了答案,因为一些信息可能很有趣,即使推理不正确。


没有短文字,因为实际上没有任何方法可以在 IL(CLR 使用的底层语言)中加载短文字。这是因为所有“短”类型(任何小于 int 的类型)在加载到操作堆栈时都会隐式扩展为 int。有符号和无符号同样是操作问题,实际上并没有与操作堆栈上的活动编号一起“存储”。 'short' 类型仅在您要将操作堆栈上的数字存储到内存位置时发挥作用,因此有 IL 操作可以转换为各种 'short' 类型(尽管它实际上仍将数字扩大回 int转换后;它只是确保该值适合存储到“短”类型的字段中。)

另一方面,长类型具有文字说明符,因为它们在操作堆栈上的处理方式不同。有一个单独的 Ldc_I8 指令用于加载常量 long 值。还有 Ldc_R4(因此为什么需要 'f' 表示浮点数)和 Ldc_R8(如果您使用不带说明符的十进制数,C# 会选择此作为默认值。)十进制是一种特殊情况,因为它实际上不是 IL 中的原始类型;它只是在 C# 中有一个内置的常量说明符“m”,可以编译为构造函数调用。

至于为什么没有特殊的短操作(以及相应的短文字),这可能是因为当前大多数 CPU 架构不使用小于 32 位的寄存器进行操作,因此在 CPU 级别上没有值得利用的区别。通过允许“短”加载 IL 操作码,您可以潜在地节省代码大小(以 IL 的字节计),但代价是增加了抖动的复杂性;节省的代码空间可能不值得。

【讨论】:

  • ("you could potentially save code size...") -- 但是有 are “短”操作码,用于保存 IL 字节(意味着 CIL 代码很短,不一定与short 数据类型有关)。例如,i4(四字节整数)甚至存在一个:ldc.i4.s 接受一个单字节参数,并将该值作为 int32 压入堆栈。来自规范:“整数 –128 到 127 有特殊的短编码(特别是 –1 到 8 的短编码)。”
  • 这个答案没有任何意义。根本错误在第一句话。如果 C# 中没有这个特性的原因是因为 C# 编译到 IL,那么为什么其他语言中的特性编译到 IL?
【解决方案4】:

因为short 可以隐式转换为intlongfloatdoubledecimal;不需要文字修饰符。

考虑:

void method(int a) {}
void method2()
{
    short a = 4;
    method(a); // no problems
}

您可能会注意到 charbyte 也带有文字修饰符,可能出于同样的原因。

From    To
sbyte   short, int, long, float, double, or decimal
byte    short, ushort, int, uint, long, ulong, float, double, or decimal
short   int, long, float, double, or decimal
ushort  int, uint, long, ulong, float, double, or decimal
int     long, float, double, or decimal
uint    long, ulong, float, double, or decimal
long    float, double, or decimal
char    ushort, int, uint, long, ulong, float, double, or decimal
float   double
ulong   float, double, or decimal

【讨论】:

  • 你的方法2展示了short => int转换,这是short s = 1;的另一个方向
【解决方案5】:

如果您声明一个文字短并使其大于Short.MaxValue,则会发生编译器错误,否则文字将是一个短。

【讨论】:

  • 文字可以很长,例如 1L。显然没有短文字这样的东西。
  • @BasB:这不太正确:您可以声明一个变量或常量short,但您必须使用非短文字对其进行初始化;正如您所注意到的,范围检查是由编译器完成的。 C# 规范 (4.0) 在第 2.4.4 节中定义了文字,对于整数文字,它说它们“用于写入类型为 intuintlongulong 的值。”
【解决方案6】:

我“在短期内工作”的时间是用于存储在数据库中的值。

它们是正整数值,很少会超过 10 到 20。(一个字节或 sbyte 就足够大了,但我认为如果代码在稍微重用的情况下被重用,稍微过度杀戮会让我不会后悔我的选择不同的方式)

该字段用于让用户对表中的记录进行排序。此表提供按“时间”排序的下拉列表或单选按钮列表(第一步、第二步……)。

作为 C# 的新手(并且足够老,可以记住计算字节数很重要),我认为它会更有效率。我不对这些值进行数学运算。我只是对它们进行排序(并在记录之间交换它们)。到目前为止唯一的数学是“MaxInUse”+1(用于新记录),这是一个特例“++MaxInUse”。这很好,因为缺少文字意味着“s = s+2”必须是“s = (Int16)(s+2)”。

现在我看到 C# 与其他 int 一起工作是多么令人讨厌,我希望加入现代世界并浪费字节,只是为了让编译器开心。

但是,“让编译器开心”不应该在我们的 10 大编程目标中排名第 65 位吗?

让编译器抱怨将整数“2”添加到任何 INTEGER 类型是否有好处?它应该抱怨“s=123456”,但情况不同。

如果有人确实需要处理数学和短裤,我建议您制作自己的文字。 (你需要多少个?)

short s1= 1, s2 = 2, s123 = 123;

那么 s = s + s2 只是有点烦人(并且让那些追随你的人感到困惑)。

【讨论】:

  • 开始思考,我应该进行测试,而不是仅仅提出一个好主意。 s = s + s2;给出与 s=s+2 相同的错误。 C# 编译器对于强类型非常烦人,一个 Short + a Short 会产生一个 Int。这可能就是为什么有几个人断言所有的数学都是用整数来完成的。基于这个测试,我提出了对原始问题的答案。不存在简短的文字,因为它永远不会有帮助。即使你有一个,你也不能将 2 个 Shorts 添加到另一个 Shorts 中。 (这让我转了一圈问为什么。但是,那是另一天的事了。)
猜你喜欢
  • 2011-07-15
  • 1970-01-01
  • 2019-10-23
  • 2014-06-09
  • 1970-01-01
  • 2018-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多