C语言 为什么在 C 和 C++ for 循环中使用 int 而不是 unsigned int?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7488837/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 09:40:53  来源:igfitidea点击:

Why is int rather than unsigned int used for C and C++ for loops?

cfor-loopintunsigned

提问by Elpezmuerto

This is a rather silly question but why is intcommonly used instead of unsigned intwhen defining a for loop for an array in C or C++?

这是一个相当愚蠢的问题,但为什么在 C 或 C++ 中为数组定义 for 循环时int通常使用它unsigned int

for(int i;i<arraySize;i++){}
for(unsigned int i;i<arraySize;i++){}

I recognize the benefits of using intwhen doing something other than array indexing and the benefits of an iterator when using C++ containers. Is it just because it does not matter when looping through an array? Or should I avoid it all together and use a different type such as size_t?

我认识到int在做数组索引以外的事情时使用的好处以及使用 C++ 容器时迭代器的好处。仅仅是因为在循环数组时无关紧要吗?或者我应该一起避免它并使用不同的类型,例如size_t

采纳答案by Jens Gustedt

This is a more general phenomenon, often people don't use the correct types for their integers. Modern C has semantic typedefs that are much preferable over the primitive integer types. E.g everything that is a "size" should just be typed as size_t. If you use the semantic types systematically for your application variables, loop variables come much easier with these types, too.

这是一个更普遍的现象,人们通常不会为他们的整数使用正确的类型。现代 C 的语义 typedef 比原始整数类型更可取。例如,“大小”的所有内容都应该输入为size_t. 如果您系统地为应用程序变量使用语义类型,那么这些类型的循环变量也会变得更容易。

And I have seen several bugs that where difficult to detect that came from using intor so. Code that all of a sudden crashed on large matrixes and stuff like that. Just coding correctly with correct types avoids that.

而且我已经看到了几个难以检测的错误,这些错误来自于使用int左右。突然在大型矩阵之类的东西上崩溃的代码。只需使用正确的类型正确编码就可以避免这种情况。

回答by 6502

Using intis more correct from a logical point of view for indexing an array.

使用int距离的视图用于索引的阵列的逻辑点更正确。

unsignedsemantic in C and C++ doesn't really mean "not negative" but it's more like "bitmask" or "modulo integer".

unsignedC 和 C++ 中的语义并不真正意味着“非负”,而更像是“位掩码”或“模整数”。

To understand why unsignedis not a good type for a "non-negative" number please consider

要了解为什么unsigned不是“非负”数字的好类型,请考虑

  • Adding a possibly negative integer to a non-negative integer you get a non-negative integer
  • The difference of two non-negative integers is always a non-negative integer
  • Multiplying a non-negative integer by a negative integer you get a non-negative result
  • 将一个可能的负整数添加到一个非负整数,你会得到一个非负整数
  • 两个非负整数之差总是一个非负整数
  • 将一个非负整数乘以一个负整数,你会得到一个非负结果

Obviously none of the above phrases make any sense... but it's how C and C++ unsignedsemantic indeed works.

显然,上述短语都没有任何意义……但这就是 C 和 C++unsigned语义确实起作用的方式。

Actually using an unsignedtype for the size of containers is a design mistake of C++ and unfortunately we're now doomed to use this wrong choice forever (for backward compatibility). You may like the name "unsigned" because it's similar to "non-negative" but the name is irrelevant and what counts is the semantic... and unsignedis very far from "non-negative".

实际上使用unsigned容器大小的类型是 C++ 的设计错误,不幸的是,我们现在注定要永远使用这个错误的选择(为了向后兼容)。您可能喜欢“无符号”这个名字,因为它类似于“非否定”,但名称无关紧要,重要的是语义……与unsigned“非否定”相去甚远。

For this reason when coding most loops on vectors my personally preferred form is:

出于这个原因,当在向量上编码大多数循环时,我个人更喜欢的形式是:

for (int i=0,n=v.size(); i<n; i++) {
    ...
}

(of course assuming the size of the vector is not changing during the iteration and that I actually need the index in the body as otherwise the for (auto& x : v)...is better).

(当然,假设向量的大小在迭代过程中没有变化,并且我实际上需要正文中的索引,否则for (auto& x : v)...更好)。

This running away from unsignedas soon as possible and using plain integers has the advantage of avoiding the traps that are a consequence of unsigned size_tdesign mistake. For example consider:

unsigned尽快避开并使用普通整数的优点是避免了由于unsigned size_t设计错误而导致的陷阱。例如考虑:

// draw lines connecting the dots
for (size_t i=0; i<pts.size()-1; i++) {
    drawLine(pts[i], pts[i+1]);
}

the code above will have problems if the ptsvector is empty because pts.size()-1is a huge nonsense number in that case. Dealing with expressions where a < b-1is not the same as a+1 < beven for commonly used values is like dancing in a minefield.

如果pts向量为空,上面的代码会出现问题,因为pts.size()-1在这种情况下是一个巨大的无意义数字。处理与常用值a < b-1不同的表达式a+1 < b就像在雷区跳舞。

Historically the justification for having size_tunsigned is for being able to use the extra bit for the values, e.g. being able to have 65535 elements in arrays instead of just 32767 on 16-bit platforms. In my opinion even at that time the extra cost of this wrong semantic choice was not worth the gain (and if 32767 elements are not enough now then 65535 won't be enough for long anyway).

从历史上看,使用size_tunsigned的理由是能够为值使用额外的位,例如能够在数组中拥有 65535 个元素,而不是在 16 位平台上只有 32767 个元素。在我看来,即使在那个时候,这个错误语义选择的额外成本也不值得获得(如果现在 32767 个元素还不够,那么 65535 个元素也不会足够长时间)。

Unsigned values are great and very useful, but NOT for representing container size or for indexes; for size and index regular signed integers work much better because the semantic is what you would expect.

无符号值很好而且非常有用,但不适用于表示容器大小或索引;对于大小和索引,常规有符号整数工作得更好,因为语义是您所期望的。

Unsigned values are the ideal type when you need the modulo arithmetic property or when you want to work at the bit level.

当您需要模算术属性或想要在位级别工作时,无符号值是理想的类型。

回答by R.. GitHub STOP HELPING ICE

It's purely laziness and ignorance. You should always use the right types for indices, and unless you have further information that restricts the range of possible indices, size_tis the right type.

这纯粹是懒惰和无知。您应该始终为索引使用正确的类型,除非您有进一步的信息来限制可能的索引范围,否则size_t就是正确的类型。

Of course if the dimension was read from a single-byte field in a file, then you know it's in the range 0-255, and intwould be a perfectly reasonable index type. Likewise, intwould be okay if you're looping a fixed number of times, like 0 to 99. But there's still another reason not to use int: if you use i%2in your loop body to treat even/odd indices differently, i%2is a lot more expensive when iis signed than when iis unsigned...

当然,如果维度是从文件中的单字节字段中读取的,那么您知道它在 0-255 范围内,并且int将是一个完全合理的索引类型。同样,int如果您循环固定的次数(例如 0 到 99)也可以。但是还有另一个不使用的原因int:如果您i%2在循环体中使用以不同方式处理偶数/奇数索引,i%2则成本要高得多何时i签名比何时i未签名...

回答by littleadv

Not much difference. One benefit of intis it being signed. Thus int i < 0makes sense, while unsigned i < 0doesn't much.

差别不大。一个好处int是它被签署。因此int i < 0是有道理的,虽然unsigned i < 0不多。

If indexes are calculated, that may be beneficial (for example, you might get cases where you will never enter a loop if some result is negative).

如果计算索引,这可能是有益的(例如,如果某些结果为负,您可能会遇到永远不会进入循环的情况)。

And yes, it is less to write :-)

是的,写得少:-)

回答by Blagovest Buyukliev

Using intto index an array is legacy, but still widely adopted. intis just a generic number type and does not correspond to the addressing capabilities of the platform. In case it happens to be shorter or longer than that, you may encounter strange results when trying to index a very large array that goes beyond.

使用int索引数组是遗留问题,但仍被广泛采用。int只是一个通用的数字类型,与平台的寻址能力不对应。如果它碰巧比这更短或更长,则在尝试索引超出范围的非常大的数组时可能会遇到奇怪的结果。

On modern platforms, off_t, ptrdiff_tand size_tguarantee much more portability.

在现代平台上,off_t,ptrdiff_tsize_t保证更多的可移植性。

Another advantage of these types is that they give contextto someone who reads the code. When you see the above types you know that the code will do array subscripting or pointer arithmetic, not just any calculation.

这些类型的另一个优点是它们为阅读代码的人提供了上下文。当您看到上述类型时,您就知道代码将执行数组下标或指针运算,而不仅仅是任何计算。

So, if you want to write bullet-proof, portable and context-sensible code, you can do it at the expense of a few keystrokes.

因此,如果您想编写防弹、可移植和上下文相关的代码,只需按几下键即可完成。

GCC even supports a typeofextension which relieves you from typing the same typename all over the place:

GCC 甚至支持一个typeof扩展,它使您无需在所有地方键入相同的类型名:

typeof(arraySize) i;

for (i = 0; i < arraySize; i++) {
  ...
}

Then, if you change the type of arraySize, the type of ichanges automatically.

然后,如果您更改 的类型arraySize,则类型i会自动更改。

回答by Jonathan Grynspan

It really depends on the coder. Some coders prefer type perfectionism, so they'll use whatever type they're comparing against. For example, if they're iterating through a C string, you might see:

这真的取决于编码器。一些程序员更喜欢类型完美主义,所以他们会使用他们正在比较的任何类型。例如,如果他们遍历 C 字符串,您可能会看到:

size_t sz = strlen("hello");
for (size_t i = 0; i < sz; i++) {
    ...
}

While if they're just doing something 10 times, you'll probably still see int:

如果他们只做 10 次,您可能仍然会看到int

for (int i = 0; i < 10; i++) {
    ...
}

回答by Shahbaz

Because unless you have an array with size bigger than two gigabyts of type char, or 4 gigabytes of type shortor 8 gigabytes of type intetc, it doesn't really matter if the variable is signed or not.

因为除非您的数组大小大于 2 GB 的 type char,或 4 GB 的 typeshort或 8 GB 的 typeint等,否则变量是否有符号并不重要。

So, why type more when you can type less?

那么,既然可以少打字,为什么还要多打字呢?

回答by Jonathan Wood

Aside from the issue that it's shorter to type, the reason is that it allows negative numbers.

除了输入较短的问题外,原因是它允许负数。

Since we can't say in advance whether a value can ever be negative, most functions that take integer arguments take the signed variety. Since most functions use signed integers, it is often less work to use signed integers for things like loops. Otherwise, you have the potential of having to add a bunch of typecasts.

由于我们无法预先确定一个值是否可以为负,因此大多数采用整数参数的函数都采用有符号数。由于大多数函数使用有符号整数,因此在循环之类的事情中使用有符号整数通常会减少工作量。否则,您可能不得不添加一堆类型转换。

As we move to 64-bit platforms, the unsigned range of a signed integer should be more than enough for most purposes. In these cases, there's not much reason not to use a signed integer.

当我们转向 64 位平台时,有符号整数的无符号范围对于大多数用途来说应该绰绰有余。在这些情况下,没有太多理由不使用有符号整数。

回答by Claudiu

I use intcause it requires less physical typing and it doesn't matter - they take up the same amount of space, and unless your array has a few billion elements you won't overflow if you're not using a 16-bit compiler, which I'm usually not.

我使用int它是因为它需要较少的物理输入,这并不重要——它们占用相同的空间,除非你的数组有几十亿个元素,否则如果你不使用 16 位编译器,你就不会溢出,我通常不是。

回答by Infinite

Consider the following simple example:

考虑以下简单示例:

int max = some_user_input; // or some_calculation_result
for(unsigned int i = 0; i < max; ++i)
    do_something;

If maxhappens to be a negative value, say -1, the -1will be regarded as UINT_MAX(when two integers with the sam rank but different sign-ness are compared, the signed one will be treated as an unsigned one). On the other hand, the following code would not have this issue:

如果max碰巧是负值,比如-1,-1则将被视为UINT_MAX(当两个具有相同等级但符号不同的整数进行比较时,有符号的将被视为无符号的)。另一方面,下面的代码不会有这个问题:

int max = some_user_input;
for(int i = 0; i < max; ++i)
    do_something;

Give a negative maxinput, the loop will be safely skipped.

给出一个负max输入,循环将被安全地跳过。