关于c:C进阶2有符号与无符号

43次阅读

共计 2505 个字符,预计需要花费 7 分钟才能阅读完成。

Summary

0)在进行数据运算、应用变量的时候,肯定要非常分明 变量的具体类型

1)对于整形数据,数据类型的最高位用于标识数据的符号:最高位为 1 示意正数,最高位为 0 示意整数

2)类型溢出时的运算总结:

  • 溢出的值为正 的:理论值为:溢出后的值 - 该类型能示意的个数
  • 溢出的值为负 的:理论值为:溢出后的值 + 该类型能示意的个数

3)十进制正数和补码的互相转换:
如何计算正数的补码:如十进制整数 -7,8 位

  1. 符号位:1
  2. 绝对值:7 <–> 0000 0111
  3. 取反:1111 1000
  4. 加 1 :1111 1001(补码)

如何从一个补码推算十进制正数:如已知(1111 1001)示意一个十进制正数
上述规定 反向 计算

  1. 减 1 :1111 1000
  2. 取反:0000 01111
  3. 绝对值:计算得 7
  4. 符号位:-7

非凡的 如 1 个字节的整数 -128,它没有原码和反码,只有补码为 1000 0000,即应用 (-0) 来示意(-128)。但依然能够应用上述规定进行推算二进制补码。

4)C 语言中的变量 默认为 有符号的类型 signed;unsigned 关键字将变量申明为无符号类型,留神: 只有整数类型 才能够申明为 unsigned

5)当无符号数和有符号数进行数学运算时,有符号数会被转换为有符号数 运算后果为无符号数

有符号与无符号数分析

1、负数和正数

数据类型的最高位用于标识数据的符号

  • 最高位为 1,标识这个数为 正数
  • 最高位为 0,标识这个书为 负数

    int sign = 0;
    
    char i = -5;
    short j = 5;
    int k = -1;
    
    sign = (i & 0x80);      // i 为正数,最高位为 1 ==> sign != 0
    sign = (j & 0x8000);    // j 为负数,最高位为 0 ==> sign == 0
    sign = (k & 0x80000000);// k 为正数,最高位为 1 ==> sign != 0

2、原码和补码

2.1 类型溢出的运算

在计算机外部用 原码示意无符号数

  • 无符号数默认为负数
  • 无符号数没有符号位

对于固定长度的无符号数

  • MAX_VALUE + 1 –> MIN_VALUE
  • MIN_VALUE – 1 –> MAX_VALUE

类型溢出时的运算总结:

  • 溢出的值为正 的:理论值为:溢出后的值 - 该类型能示意的个数
  • 溢出的值为负 的:理论值为:溢出后的值 + 该类型能示意的个数

eg1:char c = 256;

  • 剖析:有符号 char 的示意范畴为 [-128, 127],256 超过了能示意的最大值 127,因而 理论值为:溢出后的值 - 该类型能示意的个数,即 256 – 28 = 0;

    char c = 256;
    printf("c = %d\n", c);  // c = 0;

eg2:char c = -200;

  • 剖析:有符号 char 的示意范畴为 [-128, 127],256 超过了能示意的最小值 -128,因而 理论值为:溢出后的值 + 该类型能示意的个数,即 -200 + 28 = 56;

    char c = -200;
    printf("c = %d\n", c);  // c = 56;

eg3:unsigned char c = 256;

  • 剖析:无符号 char 的示意范畴为 [0, 255],256 超过了能示意的最大值 255,因而 理论值为:溢出后的值 - 该类型能示意的个数,即 256- 28 = 0;

    unsigned char c = 256;
    printf("c = %d\n", c);  // c = 0;

eg2:usigned char c = -200;

  • 剖析:无符号 char 的示意范畴为 [0, 255],-200 超过了能示意的最小值 0,因而 理论值为:溢出后的值 + 该类型能示意的个数,即 -200 + 28 = 56;

    char c = -200;
    printf("c = %d\n", c);  // c = 56;

2.2 正数如何用补码示意

在计算机外部用 补码 示意正数

  • 负数的补码就是负数自身
  • 正数的补码为正数的绝对值各位取反后加 1

    • 如:8 位整数 5 的补码为:0000 0101(负数的原码、反码、补码都一样)
    • 如:8 位整数 -7 的补码为:1111 1001

如何计算正数的补码:如十进制整数 -7,8 位

  1. 符号位:1
  2. 绝对值:7 <–> 0000 0111
  3. 取反:1111 1000
  4. 加 1 :1111 1001(补码)

如何从一个补码推算十进制正数:如已知(1111 1001)示意一个十进制正数
上述规定 反向 计算

  1. 减 1 :1111 1000
  2. 取反:0000 01111
  3. 绝对值:计算得 7
  4. 符号位:-7

3、signed 和 unsigned 关键字

  • C 语言中的变量 默认为 有符号的类型signed
  • unsigned 关键字将变量申明为无符号类型,留神:只有整数类型 才能够申明为 unsigned

    int i;          // 默认为有符号整形
    signed int j;   // 显示申明变量为带符号整形
    unsigned int k; // 申明变量为无符号整形

4、问题示例

eg.1 以下代码输入什么?

unsigned int i = 5;
int j = -10;

if((i+j) > 0)
{printf("i + j > 0 \n");
}
else
{printf("i + j <= 0 \n");
}

理论输入:(i + j > 0)。依照数学运算 -10 + 5 = -5,小于 0,应该打印 (i + j <= 0) 才是,为什么?
解析:当无符号数和有符号数进行数学运算时,有符号数会被转换为有符号数 运算后果为无符号数

  1. 计算 i + j 时,将 j 晋升为 unsigned int。
  2. -10 是一个正数,在内存中 以补码模式来存储,理论内存里的二进制值为0xFFFF FFF6(算法见上)。把 0xFFFF FFF6 以一个无符号数来解释,即此时的 j 是一个超大的数为 4,294,967,286。
  3. 而后加上 5 即为 0xFFFF FFFB,4,294,967,291。所以 i + j > 0

eg.2 以下代码输入什么?

unsigned int i = 0;
for(i = 9; i>=0; i--)
{printf("i = %u\n", i);
}

理论输入:死循环。而不是只输入 0 – 9。
解析:对于无符号整形 i,当 运算类型溢出 时,理论值会向反方向的值聚拢。

  • 当 i = 0 时,此时执行 i –,冀望 i 的值为 -1。但实际上 i 的类型是 unsigned int,能示意的范畴为 [0, 4,294,967,295]。- 1 不在能示意的范畴内,依照下面 类型溢出 时的算法,此时的理论值为:-1 + 232 = 4,294,967,295,依然大于 0。所以会不停的计算。

本文总结自“狄泰软件学院”唐佐林老师《C 语言进阶课程》。
如有错漏之处,恳请斧正。

正文完
 0