C进阶专题:数据的存储

0-a)VSCODE的Release和Debug模式

  Release生成的文件会比Debug生成的文件体积更小,同时对代码的运行进行了一定的优化,一些潜在的问题可能不会发生。

0-b)类型的基本概括

  整型家族、浮点型家族、构造类型(数组类型、结构体类型、枚举类型、联合类型)、指针类型、空类型。

1)整型家族

  我们知道整型家族有以下几种:

  • char
  • short [int]
  • int
  • long [int]
  • long long [int]

  每一类都可以再细分为signedunsighed。意味有符号和无符号

  字符的本质是ASCII码,是整型,所以也归纳到了整型家族中。占1个字节。

  int一般占4个字节。而long一般占4个字节(32位)或8个字节(64位)。

char a = 'c';

  char是有符号还是无符号取决于编译器。在VS中是默认有符号的。

2)原!反!补!

  计算机内存中用补码存储。

  正数的三码相同。

  负数的三码不同。反码为原码除符号位外按位取反。补码为反码+1。

int a = 3;

  不管左侧是什么类型,先写出3。

0000 0000 0000 0000 0000 0000 0000 0011

  这是他的32位原码表示,其中最高位位符号位,在这里为正数,为0。

  正数三码相同,这32位都可以存储下来。

char b = -3;

  同样的,先写出-3的32位原码表示。

1000 0000 0000 0000 0000 0000 0000 0011

  再写出反码。

1111 1111 1111 1111 1111 1111 1111 1100

  再写出补码。

1111 1111 1111 1111 1111 1111 1111 1101

  可是char类型只有8个bit位,会发生截断。

1111 1101

  这就是char中实际的内容。

  接下来我们对其进行输出。

printf("%d", b);

  在这里我们将其以整型输出(也就是将这8个bits视作整型32位中的一部分),先会发生整型提升,如果原来的char是有符号的,高位以符号位填充,否则一律填充0。这里默认是有符号的。

1111 1111 1111 1111 1111 1111 1111 1101

  提升完之后,会将此串补码变回原码。反码变回原码同样可以取反加一处理。

1000 0000 0000 0000 0000 0000 0000 0011

  %d是打印有符号的整型,打印出来就是-3了。

image

   经验证,答案正确。

  那要是char是无符号的呢?

unsigned char c = -3;

  同样的得到将截断后的八位存入c中。接下来进行整型提升,但是因为原来是无符号的,高位全部填充的是0。

0000 0000 0000 0000 0000 0000 1111 1101

  正数三码相同,得到的也就是原码。我们会发现得到的数就是1+4+8+16+32+64+128=253

image

  经验证,答案正确。

  等会我们再继续介绍。

3)大小端问题

  存储分为两种:大端字节序存储序和小端字节序存储。顾名思义,这样的存储是基于字节的。我们知道两位16进制的数对应的存储空间就是1MB。假如我要存储一个整型,那么有四个字节,假如在十六进制下是:

(高位)19 34 48 91(低位)

  大端字节序存储就是:高放低,低放高

低地址-高位:19 34 48 91:低位-高地址

  而小端字节序存储就是:高放高,低放低

低地址-低位:91 48 34 19:高位-高地址

  Vistual Studio就用的是小端字节序。

  我可以用一个小程序实现大小端判断吗?

#include <Stdio.h>
int main() {
    int a = 1;
    char* p = (char*)&a;
    if (*p == 1) {
        printf("Little Endian\n");
    } else {
        printf("Big Endian\n");
    }
}

  这个程序就可以实现了。原理很简单,就是原来的1为"00 00 00 01",取一个字节,看里面放的是1或0就可以了。

4)有符号和无符号的char到底能存多少!

  首先先从简单的无符号char开始入手。因为都是非负数,且不存在符号位,一共有28 种情况,对应0~28-1也就是0到255

  再来看看有符号的char,因为内存中存储的都是补码,所以我们看补码就可以了。

  第一位为符号位,我们分为两类,最高位为1/0。

  当最高位为0时候,范围类似无符号,为0到127。

  当最高位为1的时候,表示的是负数。

0000 0000 - 0
0000 0001
0000 0010
...
0111 1110
0111 1111 - 127

1000 0000 - 直接被解释为-128
1000 0001 - 变回原码就是-127
1000 0010
...
1111 1111 - 变回原码就是-1

  这样就很清楚了,我们在补码下不需要两个0,所以将1000 0000(原码解释为0000 0000)直接解释为-128。

5)值的环

image

  环中的均为补码。所有运算都是先变成补码,再加减的。那127+1会变成-128也就很容易理解了。

 

#include <stdio.h>
int main() {
    signed char a = 127;
    signed char b = 1;
    a = a + b;
    printf("%d",a);
}

  请注意,运算的时候会有整型提升,必须将其存储在char中截断出来后面八位,不然结果就是128了。截断后八位存储后,即使在打印的时候有整型提升,值也依然是-128。

posted @ 2026-01-04 20:02  Nowasiki  阅读(2)  评论(0)    收藏  举报