我一直都是,只要我记得并无处不在,就这样做了:
for (unsigned int i = 0U; i < 10U; ++i)
{
// ...
}
换句话说,我在无符号整数上使用U
说明符。现在看了很长时间,我想知道为什么我这样做。除了表示意图之外,我想不出为什么它在像这样的琐碎代码中有用的原因?
有没有一个有效的编程原因我为什么要继续这个约定,还是多余的?
答案 0 :(得分:9)
首先,我会说明你可能会看到什么,但是你的问题留有余地,所以我确保我们都在同一页上。
无符号整数与常规整数之间存在明显差异:它们的范围差异(对于int32为-2,147,483,648到2,147,483,647,对于uint32为0到4,294,967,295)。当您使用正确的bitshift >>
运算符时,在最高位上放置的位有所不同。
当您需要告诉编译器将常量值视为uint而不是常规int时,后缀很重要。如果常量超出常规int的范围但在uint的范围内,这可能很重要。如果您不使用U
后缀,编译器可能会发出警告或错误。
除此之外,Daniel Daranas在评论中提到了唯一发生的事情:如果你不使用U
后缀,你将隐式地将常量从常规int转换为UINT。这对编译器来说是一点点额外的努力,但是没有运行时差异。
10U
或0U
大多数情况下,您处于uint和int的公共范围内,因此无论是uint还是int,该常量的值看起来都完全相同。编译器将立即获取const int表达式并将其转换为const uint。
那就是说,这是我能给你的唯一一个论点:语义。使代码在语义上连贯起来很不错。在这种情况下,如果你的变量是一个uint,那么将该值设置为常量int是没有意义的。如果你有一个uint变量,它显然是有原因的,它应该只适用于uint值。
但是,这是一个非常弱的论点,特别是因为作为读者,我们接受uint常量通常看起来像int常量。我喜欢一致性,但使用&#39; U&#39;没有任何好处。答案 1 :(得分:4)
我在使用定义时经常会看到这一点,以避免签名/未签名的不匹配警告。我为使用不同工具链的几个处理器构建了代码库,其中一些处理器非常严格。
例如,删除MAX_PRINT_WIDTH定义中的'u':
#define MAX_PRINT_WIDTH (384u)
#define IMAGE_HEIGHT (480u) // 240 * 2
#define IMAGE_WIDTH (320u) // 160 * 2 double density
发出以下警告: &#34; .. \ Application \ Devices \ MartelPrinter \ mtl_print_screen.c&#34;,第106行:cc1123:{D}警告: 无符号类型与有符号类型的比较
for ( x = 1; (x < IMAGE_WIDTH) && (index <= MAX_PRINT_WIDTH); x++ )
你可能也会看到'f'代表浮动与双倍。
答案 2 :(得分:4)
我从评论中提取了这句话,因为它是一个广为人知的不正确的陈述,也因为它提供了一些明确标记无符号常数的原因,因为这是一个好习惯。
...当我认为溢出可能是一个问题时,似乎只保留它才有用吗?但话说回来,我没有通过某种方式指明无符号来减轻这种情况......
现在,让我们考虑一些代码:
int something = get_the_value();
// Compute how many 8s are necessary to reach something
unsigned count = (something + 7) / 8;
那么,unsigned
是否会减少潜在的溢出?完全没有。
假设something
原来是INT_MAX
(或接近该值)。假设一台32位机器,我们可能期望count
为2 29 或268,435,456。 But it's not.
告诉编译器计算的结果应该unsigned
对计算的输入没有任何影响。由于something
是int
,而7
是int
,something + 7
将被计算为int
,并且会溢出。然后,溢出的值将除以8(也使用带符号的算术),无论有什么用,都将转换为unsigned
并分配给count
。
使用GCC,算术实际上以2s补码执行,因此溢出将是一个非常大的负数;在划分之后,它将是一个不那么大的负数,并且最终是一个较大的无符号数,比我们期望的数字大得多。
假设我们已经指定了7U
(也许8U
也是如此,以保持一致)。 Now it works.。它的工作原理是因为现在something + 7U
是用无符号算术计算的,它不会溢出(甚至包裹。)
当然,这个错误(和成千上万的人一样)可能会被忽视很长一段时间,在最糟糕的时刻爆炸(也许是字面意思)......
(显然,使something
无符号会缓解问题。这里非常明显。但定义可能距离使用还有很长的路要走。)
答案 3 :(得分:1)
你应该为简单的代码 1 执行此操作的一个原因是后缀强制文字上的类型,并且类型对于产生正确的结果可能非常重要。
考虑一下(有些愚蠢)代码:
and loginname!='abc123'
根据他们的论证类型,不难想象这些功能实际上是在做一些有意义的事情。如果我省略了后缀,那么泛型选择会产生一个非常简单的调用的错误结果。
1 但也许不是你帖子中的特定代码。
答案 4 :(得分:-1)
在这种情况下,它完全没用。
在其他情况下,后缀可能很有用。例如:
#include <stdio.h>
int
main()
{
printf("%zu\n", sizeof(123));
printf("%zu\n", sizeof(123LL));
return 0;
}
在我的系统上,它将打印4然后8。
但回到你的代码,是的,它使你的代码更加明确,仅此而已。