我应该使用无符号整数来计算成员吗?

jpf*_*ius 9 delphi integer-overflow

我应该为计数类成员使用无符号整数吗?

回答

例如,假设一个类

TList <T> = class
private
  FCount : Cardinal;
public
  property Count : Cardinal read FCount;
end;
Run Code Online (Sandbox Code Playgroud)

这确实有道理,不是吗?列表中存储的项目数不能为负数,那么为什么不使用无符号整数类型呢?我认为总是使用最不通用的(最特殊的)类型是一个很好的原则.

现在,迭代列表如下所示:

for I := 0 to List.Count - 1 do
  Writeln (List [I]);
Run Code Online (Sandbox Code Playgroud)

当列表中存储的项目数为零时,编译器会尝试进行评估

List.Count - 1
Run Code Online (Sandbox Code Playgroud)

这导致一个很好的整数溢出(确切地说是下溢).结合调试器没有显示发生异常的适当位置的事实,这对我来说很难找到.

让我补充一点,如果你关闭溢出检查,结果错误将更难跟踪,因为那时你经常会访问不属于你的内存 - 这会导致未定义的行为.

从现在开始,我将为所有计数成员使用普通整数来避免这种情况.

如果这完全是胡说八道,请指出给我:)

(我只花了一个小时跟踪代码中的整数溢出,所以我决定分享一下 - 当然大多数人都会知道,但也许我可以节省一些时间.)

Ste*_*ont 15

不,绝对不是.Delphi习语是在这里使用整数.不要对抗语言.在32位环境中,除了尝试构建位图之外,列表中没有更多元素.

让我们明确一点:每个将要使用您的代码的程序员都会讨厌使用Cardinal而不是整数.

  • 这个成语有几个原因 - 1. MaxListSize = Maxint div 16,因此它无法获得无符号整数.2.如果找不到项,IndexOf()类型函数返回-1,因此它们需要是整数.列表不能大于可用内存! (2认同)

Bar*_*lly 10

无符号整数几乎总是比它们的值更麻烦,因为你通常最终会在表达式中混合有符号和无符号整数.这意味着需要扩展类型(并且可能具有性能损失)以获得正确的语义(理想情况下编译器根据语言定义执行此操作),否则您需要在范围检查中非常小心.

以C/C++为例:size_t是内存大小和分配的整数类型,是无符号的,但是ptrdiff_t当你从另一个指针中减去一个指针时,你得到的偏移的类型,必然是有符号的.想知道你在阵列中分配了多少元素?也许您从first元素地址中减去last+1元素地址并除以sizeof(element-type)?好吧,现在你只是混合了有符号和无符号整数.


pax*_*blo 9

关于你的陈述"我认为总是一个好的原则,总是使用最不通用的(最特殊的)类型." - 实际上我认为使用最不会引起焦虑和麻烦的数据类型是一个很好的原则.

一般对我来说,这是一个签名的int,因为:

  1. 我通常没有包含2 31或更多元素的列表.
  2. 你不应该有那么大的名单:-)
  3. 我不喜欢在我的代码中遇到特殊边缘情况的麻烦.

但这确实是一个风格问题.如果代码的"纯度"对于您而言比简洁代码更重要,那么您的方法最好(通过修改来捕获边缘情况).我自己,我更喜欢简洁,因为边缘情况往往会混乱代码并减少理解.


Eri*_*nge 8

别.

它不仅仅违背了编程习惯用法,它是对编译器使用无符号算法的明确请求,它要么容易出现异常行为(如果你不防止溢出),要么发生不相关的运行时异常(如果你防止溢出,临时溢出将是致命的,当你在添加之前减去fi时,即使最终结果是肯定的,我指的是操作的CPU操作码级别顺序,这可能与你在你的内容中没有任何关系.码).

请记住"无符号"并没有转化为"积极",将其翻译为"没有迹象",这是不同的.选择"无符号"一词是有充分理由的(在Delphi中将其命名为"红衣主教"是一个糟糕的选择IMO).

无符号类型用于原始存储规范,按位操作,ASM代码,嵌入式控制器和其他专业用途.当你进行高级编程时,你应该忘记你曾经听说过无符号类型.