使用uint vs int [关闭]


83

我观察了一段时间,C#程序员倾向于在所有地方使用int,很少使用uint。但是我从来没有找到一个令人满意的答案。

如果您希望互操作性成为目标,那么uint不应出现在公共API中,因为并非所有的CLI语言都支持无符号整数。但这并不能解释为什么int如此流行,即使在内部类中也是如此。我怀疑这是uint在BCL中很少使用的原因。

在C ++中,如果您有一个没有负值的整数,则选择一个无符号整数。

这显然表示不允许或期望使用负数,并且编译器将为您做一些检查。我还怀疑在数组索引的情况下,JIT可以轻易放弃下限检查。

但是,在混合int和单位类型时,需要格外小心和强制转换。

应该更多使用uint吗?为什么?



刚刚想到我有一个deja vu:D,不久前提出的问题几乎完全相同。
KroaX 2010年

至于下限检查(如果需要自己编写),可以替换if (i < 0 || i >= length)if (unchecked((uint)i) >= length)。产生的IL总共将少一个(分支)指令,并且将提供大致相同的性能(无限快)。就个人而言,我之所以喜欢它,只是因为它使我不愿意检查下限。其他人可能会因为“未经检查”而反对它,但是我认为这是了解其含义的一条很好的路线,因为它很简单并且可以从上下文中立即明确目的是什么,可以帮助读者学习。
AnorZaken 2015年

忘了提及上面的方法在64位版本上是最佳的,因为它将执行64位比较。对于32位版本,if (unchecked((uint)i) >= unchecked((uint)length))可提供更好的性能。但是,这确实令人费解,并且64位比较仍比32位构建中的标准双分支界限检查更有性能,因此在任何合理的情况下我都不能真正推荐这样做。(我主要是为了指出这一点,否则将使用64位比较-这对某些人可能是有用的信息。)
AnorZaken 2015年

先生们,我认为您的主要意见基础不好。如果有一个客观的答案,我想听听。我全心全意为自己的利益而改变我的做法。
2015年

Answers:


50

uint我怀疑,您对为什么不在BCL中使用的观察是主要原因。

UInt32不符合CLS,这意味着它完全不适合在公共API中使用。如果您要在私有API中使用uint,则意味着要转换为其他类型-保持类型不变通常更容易也更安全。

我还怀疑这在C#开发中并不常见,即使C#是唯一使用的语言,主要是因为它在BCL中并不常见。通常,开发人员尝试(感激地)模仿他们所构建的框架的样式-在C#的情况下,这意味着尝试使您的API(公共的和内部的)看起来尽可能类似于.NET Framework BCL。这意味着要谨慎使用uint。


1
stackoverflow.com/questions/2013116/…是一个涉及类似主题的问题
Stephan

77

int比短uint


2
我怀疑这很接近事实。为什么uint在99%的时间(以我的经验)int足够的情况下使用?
马修·琼斯

12
@贾斯汀:像“ -1”这样的“魔术数字”通常不是一个好主意。切换到长距离意味着无缘无故地使用2x内存...如果您不需要与其他API交互,“单元”绝对很有价值。
Reed Copsey 2010年

28
我从不习惯使用int索引数组,因为我永远不会有负索引。似乎很明显uint在这种情况下应使用a 。
Mark H

2
更不用说,更具可读性。如果您曾经将自己的代码/算法传递给其他人,但可能比您缺乏经验,那么使用大量的代码/算法可能会使uint它们挂起来。int非常适合在您控制范围的所有情况下使用。
drharris 2010年

3
@MarkH完全一致,但这样做反向迭代时,它可以在形式有用:for (int i = arr.Length - 1; i >= 0; i--) { }。用uint这样做会导致溢出异常,甚至更糟的是,无限循环。
Aidiakapi 2014年

19

通常int就足够了。如果可以满足以下所有条件,则可以使用uint

  • 它不适用于公共API(因为uint它不符合CLS)。
  • 您不需要负数。
  • 您(可能)需要其他范围。
  • 没有将它与进行比较< 0,因为从来没有这样做true
  • 没有将它与进行比较>= 0,因为从来没有这样做false

最后一个要求经常被遗忘,并且会引入一些错误:

static void Main(string[] args)
{
    if (args.Length == 0) return;
    uint last = (uint)(args.Length - 1);

    // This will eventually throw an IndexOutOfRangeException:
    for (uint i = last; i >= 0; i--)
    {
        Console.WriteLine(args[i]);
    }
}

13

1)坏习惯。说真的 即使在C / C ++中。

想想常见的for模式:

for( int i=0; i<3; i++ )
    foo(i);

绝对没有理由在那里使用整数。您永远不会有负值。但是几乎每个人都会以这种方式进行简单的循环,即使它包含(至少)另外两个“样式”错误也是如此。

2)int被视为机器的本机类型。


4

我喜欢uintint除非负数实际上是可接受的值的范围内。特别是,接受一个int参数,但是ArgumentException如果数字小于零则抛出一个正太傻了–使用uint

我同意uint未充分利用,并鼓励其他所有人更多地使用它。


7
仅接受单元而不检查边界是非常危险的。如果有人传递一个负值,则CLR会将其解释为大整数,这意味着-1时您会得到uint.maxvalue。这是不希望的行为。
亨利

19
@Henri:C#没有从int到uint的隐式转换,因此没有“如果有人传递负值”。当然,对上限进行边界检查仍然是适当的(但是现在您只需要检查一次即可,而不是两个)。
Ben Voigt 2010年

1

我在较低级别的应用程序层进行编程,在这些应用程序中,int很少会超过100,因此负值不是问题(例如,对于i <myname.length()类型的东西),这只是一个古老的C习惯-而且如上所述,键入起来更短。但是,在某些情况下,当连接到我要处理来自设备的事件标志的硬件时,在标志可能使用最左(最高)位的情况下,uint很重要。

老实说,对于我99.9%的工作,我可以轻松使用ushort,但是int听起来比ushort好很多。


1

我已经用C#制作了Direct3D 10包装器,并且如果我想创建非常大的顶点缓冲区,则需要使用uint。视频卡中的大缓冲区不能用带符号的int表示。

UINT非常有用,否则就傻了。如果有人因为仅仅因为不需要使用uint而认为其他任何人都不会使用,那么您错了。


这是一个很好的案例,您可以利用更大的范围。
Leo Gurdian'3

0

我认为这只是懒惰。C#本质上是在具有相对大量资源的台式机和其他计算机上进行开发的选择。

但是,C和C ++根植于内存稀疏的旧系统和嵌入式系统中,因此程序员习惯于仔细考虑要使用哪种数据类型。C#程序员很懒,而且由于通常有足够的资源,因此没有人真正优化内存使用(通常,当然并非总是如此)。如果一个字节就足够了,那么很多C#程序员,包括我在内,都只是为了简化而使用int。而且,许多API函数都接受int,因此可以防止强制转换。

我同意选择正确的数据类型是一种好习惯,但是我认为主要动机是懒惰。

最后,选择一个整数在数学上更正确。数学中不存在无符号整数(仅自然数)。而且由于大多数程序员都有数学背景,所以使用整数更为自然。


我不会说这是懒惰,尽管懒惰有其优点。在大多数情况下,更多的是,我只是不太关心int / uint的事情,浪费我的脑力去做这样的决定,而只是选择int。硬件便宜,程序员可能很昂贵。
SWeko

程序员是懒惰的。那是一件坏事。雷蒙德会说程序员讨厌缴税!
lornova

我将是第一个让我们的C#程序员懒惰的管理员,但这不一定是一件坏事。
ChaosPandion

@Lorenzo,我在大学里写了一篇文章,指出一个懒惰的程序员是一个好的程序员。大多数情况下,它是关于优化程序员时间而不是机器时间。
Eloff 2010年

1
嗯,我见过(或做过)的大多数程序员难以置信的错误都是由懒惰引起的……
lornova 2010年

0

我认为,很大一部分原因是当C首次出现时,int为简洁起见,大多数示例都使用了。我们为不必integer像使用Fortran和Pascal那样编写而感到高兴,并且在那些日子里,我们通常将它们用于平凡的事情,例如数组索引和循环计数器。无符号整数是需要保留最后一位的大数的特殊情况。我认为C习惯继续发展到C#和其他新语言(例如Python)是很自然的进步。


0

某些语言(例如Pascal的许多版本)将无符号类型视为数字。通常将执行无符号类型和相同大小的带符号类型之间的操作,就像将操作数提升为下一个更大的类型一样(在某些此类语言中,最大类型没有无符号等效项,因此这种提升始终是可能的)。

其他语言(例如C)将N位无符号类型视为一个以2 ^ N为模的分组。请注意,从此类组的成员中减去N并不表示数值相减,而是产生了组成员,当将其添加N时,将产生原始成员。可以说,某些涉及带符号和无符号值混合的操作实际上没有意义,应该被禁止,但是即使是对诸如数字文字之类的东西特别草率的代码也能正常工作,并且编写了混合有符号的代码和无符号类型,尽管草率,但确实可以正常工作,因此该规范不易在短期内更改。

仅解决带符号的类型要比计算带符号的类型和无符号的类型之间所有复杂的交互要容易得多。当将较大的数字分解为较小的部分(例如,用于序列化)或重构此类数字时,无符号类型很有用,但通常最好对实际代表数量的事物使用带符号的数字


0

我知道这可能是一个旧线程,但是我想澄清一下。

让我们以int8表示,您可以存储–128到127,它使用1个字节,共127个正数。
当您使用int8时,其中一位用于负数-128。
使用Uint8时,请将负数赋予正数,这样就可以使用255个正数,且存储1字节的空间相同。
唯一的缺点是您现在已经失去了使用负值的功能。
另一个问题是,并非所有的编程语言和数据库都支持此功能。
在我看来,您会使用此功能的唯一原因是,当您需要像游戏编程那样高效时,必须存储大量的非负数。这就是为什么没有很多程序使用它的原因。

主要原因是存储不是问题,您不能与其他软件,插件,数据库或Api灵活地使用它。同样,例如,银行将需要负数来存储货币等。

希望对您有所帮助。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.