C语言整型——整型的取值范围:(一)无符号整型的取值范围

limits.h 的不足

通过库 limits.h 中的常量,我们可以得知绝大多数整型的范围。但是其中并没有 long long 类型的取值范围。在 C++ 的库 climits 中定义了常量 LLONG_MIN, LLONG_MAX, ULLONG_MAX,但是这并不在 C 语言的范畴中。我们希望有一种方法,可以得到 C 语言中任意整型数据的取值范围。

根据编码的原理的不同,有符号类型和无符号类型要分开讨论。我们先讨论有符号整型。

有符号整型的编码

假设用 n n n 位(以下例子中 n = 8 n=8 n=8)来存储一个整数,用最高位作为符号位,那么这个整数的取值范围应当是 ( − 2 n − 1 , 2 n − 1 ) (-2^{n-1},2^{n-1}) (2n1,2n1) 考虑到 0 0 0,实际取值范围是 ( − 2 n − 1 , 2 n − 1 − 1 ) (-2^{n-1},2^{n-1}-1) (2n1,2n11)

正数的编码就是其本身的二进制数,所以 2 7 − 1 2^7-1 271的二进制数就是 01111111,而负数采用补码的方式存储,是其原码非符号位取反加一。例如 − 1 -1 1 的原码为 10000001,反码为11111110,补码为 1111111

− 2 7 + 1 -2^7+1 27+1 的原码为 1111111,反码为 10000000,补码为 1000001。整数每-1,原码就+1,反码就-1,补码也-1。

这样又体现了补码的好处。因为按照原码, 2 n − 1 2^{n-1} 2n1 是无法表示的,那么 − 2 n − 1 -2^{n-1} 2n1 也就无法表示。某种角度上说也是因为原码有 − 0 -0 0,即就是 10000000 的存在。相应的反码也有这样的问题,因为在反码中 11111111 被 − 0 -0 0 所使用,导致 − 2 7 + 1 -2^7+1 27+1 就已经到了 10000000 10000000 10000000。但是在补码中,我们有 10000001-1=10000000,用 10000000 来表示 − 2 7 -2^7 27 就十分的平凡了。

计算方法

也就是说,8位整型的最小值为10000000,最大值为01111111。通过二进制运算 1<<7~(1<<7) 我们可以分别得到这两个数。

将这种方法拓展,则有符号整型的最小值和最大值分别为 1<<sizeof(type) - 1,~(1<<sizeof(type) - 1)

需要注意的是,有时 long 和 long long 的位数高于 int。我们不妨假设分别为16、32、64位。1 默认是一个 int 类型的数,在 1<<31 时会溢出而丢弃最高位,得到0的结果。所以我们应当使用 1L<<sizeof(long) - 11LL<<sizeof(long long) - 1 的方法。

但是 C 总是充满了奇奇怪怪的特例。

需要注意的地方

以 int 传递 short

首先要说的就是在传参的时候,short 类型会以 int 类型来传递。这可能是因为 int 往往是一个计算机的字长,具有更高的传输效率。例子如下:

short int b = 1;	

printf("%hd, %d\n", b<<16, b<<16);
printf("%d, %lld\n", 1<<32, 1<<32);

// 输出结果:
// 0, 65536
// 0, 0

这是因为 b<<16 实际上是作为一个int被传输,就使得其并没有产生之前的溢出归零的问题。

取模位移

另一个特例是,如果变量向左移位多于存储位数,会对存储位数取模然后移位。但是常量和short不会。如下:

short a = 1;
int b = 1;
long c = 1;
long long d = 1;

printf("%hd\n", a<<18);
printf("%d, %d\n", 1<<34, b<<34);
printf("%ld, %ld\n", 1L<<34, c<<34);
printf("%lld, %lld\n", 1LL<<66, d<<66);	

// 输出结果:
// 0
// 0, 4
// 0, 4
// 0, 4

并且short不取模,不是因为它作为 printf() 的参数以int被传输,而是它真的不会取模。如下所示:

short a = 1, aa = 3;

aa = a<<18;

printf("%hd, %hd\n", a<<18, aa);

// 输出结果:
// 0, 0
  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言的变量类型包括整型、浮点型、字符型和指针型等。 整型变量用于存储整数,包括有符号和无符号类型。有符号类型可表示正、负整数,无符号类型只能表示非负整数。取值范围主要取决于所使用的编译器和机器平台,通常有char(1字节,范围-128到127或0到255)、short(2字节,范围-32768到32767或0到65535)、int(4字节,范围-2147483648到2147483647或0到4294967295)、long(4或8字节,范围因平台而异)、long long(8字节,范围因平台而异)等。 浮点型变量用于存储实数,包括单精度和双精度类型。单精度浮点数通常为4字节,双精度浮点数通常为8字节。取值范围也因平台不同而有所差异,但一般单精度范围约为1.2e-38到3.4e38,双精度范围约为2.3e-308到1.7e308。 字符型变量用于存储单个字符,占用1字节。字符类型可表示ASCII字符,取值范围为0到127,或者使用wchar_t类型表示更广泛的字符集。 指针型变量用于存储内存地址,用于访问和操作其他变量。指针的大小根据所在平台而定,一般为4或8字节。指针的取值范围可能占用整个地址空间,但具体大小取决于计算机的架构和操作系统。 总结而言,C语言变量的类型和取值范围因平台和编译器而异,但通常整型、浮点型、字符型和指针型是基本的类型,其取值范围由不同数据类型和计算机架构决定。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值