在C++中什么时候需要使用'int'?

8

我知道标题看起来有点傻,但请耐心听我说一下。

自从我开始使用 size_tptrdiff_t 以来,就再也没有用过 int 了,至少我能记得的有这么久。

我最近记得使用的唯一整数数据类型属于以下某一类别之一:

  1. (无符号) 整数与内存中某些数据结构(例如 vector)中的索引相关联。
    几乎总是,此类情况下最适合使用的类型为 size_t (或者如果你想多做一些努力,则是 ...::size_type)。
    即使该整数实际上并不代表索引,通常它仍然与某个索引相关联,因此 size_t 仍然适用。

  2. size_t 的有符号版本。在许多情况下,对于此类问题,似乎最适合的类型是 ptrdiff_t,因为通常情况下,当您需要此类型时,您正在使用迭代器--因此对它们来说,size_tptrdiff_t 都是适用的。

  3. long。我偶尔需要这个用于 _InterlockedIncrement(参考计数)。

  4. (unsigned) long long,用于保存文件大小。

  5. unsigned intunsigned long,用于 "计数" 目的(例如,每 100 万次迭代,更新 UI)。

  6. unsigned char,用于对内存进行原始字节级访问。
    (附注:我从未发现使用过 signed char 的场景。)

  7. intptr_tuintptr_t,偶尔用于存储操作系统句柄、指针等。

重要的是,int 的一个特定方面是您不应该溢出它(因为这是未定义行为),因此您甚至不能可靠地将其用于计数--尤其是如果您的编译器将其定义为 16 位。

那么,何时应该使用 int 呢(除了当你的依赖项已经要求使用它时)?
在新编写的可移植代码中,现在是否还有任何真正的用途?


2
在什么情况下定义 operator++(int) ? :) - Yuushi
3
请阅读此文: https://dev59.com/w3RB5IYBdhLWcg3wCjjO简述: int 是一个内置类型,而 size_t 是一个宏定义。int 可以表示负数,这对于... 数学运算来说很有用吗?是认真的。 - KSchmidt
1
@KSchmidt 无论它被编译成什么,它仍然是一个无符号类型。 - Yuushi
1
@KSchmidt 我怀疑在大多数实现中,size_tptrdiff_t没有被typedef为(unsigned) intlong除外(64位Windows除外)。 - Daniel Fischer
1
@KSchmidt 我并不质疑有符号的32位整数类型的实用性。我质疑你在上面的评论中声称 size_t/ptrdiff_t 在大多数实现中都被 typedef 为 (unsigned) int。在大多数64位平台上它们并不是,即使在我的32位平台上,它们在我使用的所有编译器中都被 typedef 为 (unsigned) long - Daniel Fischer
显示剩余11条评论
4个回答

9
最重要的理由是可读性(以及简单的数学)。
long weeklyHours = daysWorked * hoursPerDay;

"好的...不过再说一遍,人类每周实际需要工作多少小时才需要一个的时间呢?"

size_t weeklyHours = daysWorked * hoursPerDay;

"等一下...我们是在使用 weeklyHours 来遍历向量吗?"

unsigned int weeklyHours = daysWorked * hoursPerDay;

"足够清晰。" - 如果任何一个数值可以为负数,可能会导致错误(这是逻辑的一部分 - 这可能是一种考虑休假或离开时间的方式,但不重要)

int weeklyHours = daysWorked * hoursPerDay;

"好的,很简单。我明白这段代码在做什么了。"


我不理解,这不应该使用unsigned int吗?为什么允许负数,当在你的代码中应该没有负数? - user541686
我认为unsigned weeklyHours = daysWorked * hoursPerDay;看起来最易读,但我可以理解这可能会有争议,所以点赞。不过希望能有更有说服力的建议。 ;) - user541686
@Mehrdad 我知道使用 unsigned 的优点,但对我个人来说,它只让我想到溢出和位操作。 - Luchian Grigore
哈哈... 我的情况正好相反。当我看到 int 时,我首先想到的是,天啊,这个会不会溢出?!然后我想到的第二件事是,它什么时候是负数? - user541686
2
@Mehrdad 我同意Luchian的观点,无符号值溢出时你将毫无察觉 - 如果你的无符号值为0,并且至少减去1,那么它会变成一个巨大的数。对于大多数情况来说,int类型的值范围足够表示,并且不会出现“哎呀,我减了1,现在得到了一个巨大的数”的问题。 - KSchmidt
1
@Mehrdad:通常情况下,当只需要额外值从2^31...2^32左右时,使用int可能会溢出,而使用unsigned则是安全的...这种情况比在表达式中生成(即使只是临时的)“错误”0值要少得多。 - Tony Delroy

6
Luchian提出了一些很好的易读性观点,我将添加一些技术上的观点:
编译器期望选择一个对于处理高效的int大小,而long可能不是(每操作风险更多的CPU周期,更多的机器代码字节,需要更多的寄存器等)。 使用带符号类型可以消除一些错误,例如: abs(a - b)数学上看起来没问题,但在b>a且它们无符号时不能给出直观结果 int second_delta = (x.seconds - y.seconds) + (x.minutes - y.minutes) * 60; if(pending - completed > 1) kick_off_threads(); 在需要积分标记值时,通常使用-1:对于无符号类型,这将被转换为最大可能值,但这可能会导致误解和编码错误(例如if(x> = 0)测试非标记) 此外,有许多隐式转换可以在有符号和无符号整数之间进行-重要的是要理解,无符号类型很少有助于强制实施"非负"不变量:如果这是吸引人的部分,则最好编写具有构造函数和运算符以强制执行不变量的类。
就易读性而言,int表示需要清晰跨越问题域的数字的一般需求-这可能过度,但是众所周知这在机器代码操作和CPU周期中很便宜,因此是一般整数存储的首选类型。如果您开始使用unsigned char存储某人的年龄-它不仅不能很好地与operator<<(std :: ostream&...)配合使用,而且会引发类似于“是否有必要在这里保存内存?”(对于基于栈的变量尤其令人困惑),"是否有意将其视为用于I / O或IPC目的的二进制数据?“或甚至”是否是已知单个数字年龄以ASCII形式存储的?“如果某些东西最终可能会在寄存器中,int是自然的大小。

+1 表示 abs(a-b)。我曾经遇到过类似的 bug,花了很长时间才弄清楚问题所在。 - Leo

0

我终于找到了一个好的用例:

int 是存储整数对数的完美选择,例如地图上的缩放级别。

short 通常没有足够的精度(平滑鼠标滚轮的旋转可以非常精确),而 long 则通常比我们需要的更精确。
我们肯定需要负值,因此不应使用无符号类型。因此,int 很适合这个任务。


0

假设您正在为银行账户编写程序。如果您取出的金额过多(某些账户允许您这样做,但需要缴纳罚款),那么您将需要以某种方式表示负值。


在我看来,银行账户应该使用long long数据类型,例如美国目前的预算等。=P - user541686
@LuchianGrigore那么问题是什么?一个单一的有符号变量类型?那么那些基于大量#define的类型呢,但是没有人对此有问题吗?完全令人困惑。 - KSchmidt
@KSchmidt 是的,我也这么认为。OP提供了“long”作为替代方案,它是有符号的。 - Luchian Grigore

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接