一些应该使用无符号整数类型的情况包括:
- 您需要将数据作为纯二进制表示。
- 您需要使用无符号数获得模算术的语义。
- 您必须与使用无符号类型的代码进行接口交互(例如,接受/返回
size_t
值的标准库例程)。
但是对于一般的算术运算,有一点需要注意:当你说某个值“不能为负”,这并不一定意味着你应该使用无符号类型。因为您可以将负值放入无符号类型中,只是当您取出时它将变成一个非常大的值。所以,如果您的意思是禁止使用负值,比如基本平方根函数,那么您正在说明函数的前提条件,并且您应该使用断言。而不能断言不能存在的内容,您需要一种方式来保存带外值,以便进行测试(这与 getchar()
返回 int
而不是 char
的逻辑相同)。
此外,有符号和无符号的选择也可能对性能产生影响。请看下面(人为制造的)代码:
#include <stdbool.h>
bool foo_i(int a) {
return (a + 69) > a;
}
bool foo_u(unsigned int a)
{
return (a + 69u) > a;
}
除了参数类型不同外,两个foo函数是相同的。但是,当使用c99 -fomit-frame-pointer -O2 -S
编译时,您会得到:
.file "try.c"
.text
.p2align 4,,15
.globl foo_i
.type foo_i, @function
foo_i:
movl $1, %eax
ret
.size foo_i, .-foo_i
.p2align 4,,15
.globl foo_u
.type foo_u, @function
foo_u:
movl 4(%esp), %eax
leal 69(%eax), %edx
cmpl %eax, %edx
seta %al
ret
.size foo_u, .-foo_u
.ident "GCC: (Debian 4.4.4-7) 4.4.4"
.section .note.GNU-stack,"",@progbits
你可以看到foo_i()
比foo_u()
更有效率。这是因为无符号算术溢出被标准定义为“环绕”,所以如果a
非常大,(a + 69u)
可能会比a
小,因此必须有代码处理这种情况。另一方面,有符号算术溢出是未定义的,因此GCC将假定有符号算术不会发生溢出,因此(a + 69)
永远不会小于a
。因此,盲目选择无符号类型可能会不必要地影响性能。