存储结构学习笔记

C语言类型

  1. 内置类型

    char

    short

    int

    long

    float

    double

  2. 自定义类型(构造类型)

以及他们所占存储空间的大小。类型的意义在于:

  1. 使用这个类型开辟存储空间的大小(大小决定了使用范围)
  2. 如何看待内存空间的视角。

整形的基本归类

整形家族:

  1. char

    unsigned char

    signed char

  2. short

    unsigned short[int]

    signed short[int]

  3. int

    unsigned int

    signed int

  4. long

    unsigned long

    signed long

    浮点型家族

    1. float

    2. double

    构造类型

数组类型

结构体类型

枚举类型 enum

联合类型 union

指针类型

  1. int *pi;
  2. char *pc;
  3. float *pf;
  4. void *pv;

空类型

void表示空类型(无类型)

通常应用于函数的返回类型,函数的参数,指针类型。

注意:

  1. void 是类型,不能定义变量,空类型对应的大小是0,。所以 void 无法开辟空间,即无法定义变量。

  2. 虽然 void 在linux 系统下大小为 1 个字节,但是系统认定 void 为空类型,同样无法定义变量。

  3. 虽然 void 不能定义变量,但是 void* 可以,在 32 为平台下,任何指针的大小都是4个字节,但是不能解引用。

  4. C 语言中函数的返回值类型可以省略,但是省略之后默认为 int。

  5. void* 可以接收任何类型。

整形在内存中的存储

变量的创建是需要在内存中开辟空间的。空间的大小是根据不同的类型而决定的。

那接下来我们谈谈数据在开辟内存中是如何存储的?

比如:

int main()
{
	int a = 10;
	int b = -20;
	return 0;
}

我们知道a分配四个字节的空间,那如何存储?

下面我们了解以下概念:

原码,反码,补码

计算机中的有符号数有三种表达形式,即原码,反码和补码。

三种表示方法均有符号位和数值位两部分,符号位都是0表示正,用1表示负。

三种表示方法各不相同

原码:直接将二进制按照正负数的形式翻译成二进制形式就可以了

反码:将原码的符号位不变,其余位依次按位取反就可以了。

补码:反码+1就得到补码

正数的原码,反码,补码都相同。

对于整形来说:数据存放内存中其实存放的是补码。

这是为什么呢?

在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理,同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码与源码相互转换,其运算过程是相同的,不需要额外的硬件电路。

我们看看在内存中的存储:

变量a在内存中的存储:

因为a为正数,所以在存储的时候先将十进制数,转化为二进制数原码,并且因为是正数,所以原、反、补码相同,不用转化。

变量b在内存中的存储:

因为b为负数,在进行十进制转化为二进制原码后,要进行原码和补码之间的转化,转化过程为符号位不变其他位按位取反,再加一。

可是有没有觉得怪怪的?为什么数字是反过来排列的?难道不是应该是 00 00 00 14 和 ff ff ff f6 吗?

这里就要引入小端存储和大端存储。

数据是有高、低位之分的,内存地址是有高、低地址之别的。

小端存储模式:是指数据的低位保存在内存的低地址中;而数据的高位,保存在内存高地址中。

上图就是小端存储。

大端存储:是指数据的低位保存在内存的高地址中;而数据的高位,保存在内存低地址中。

注意:整数:

1.有符号数:正数:原码,反码,补码相同

​ 复数:原码,反码,补码不同,要进行计算

2.无符号数:原码,反码,补码相同

实例

百度2015年系统工程师笔试题

请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序。

分析一下

int a=20;//0x00 00 00 14
//小端:14 00 00 00
//大端:00 00 00 14

我们只需要拿出第一个数字,如果14就是小端,如果00就是大端。

通过这个思想,我们可以写出一个简单的代码:

#define <stdio.h>
int main()
{
	int a = 1;
	char* p =(char*) &a;
	if (*p == 1)
	{
		printf("这是小端存储\n");
	}
	else
	{
		printf("这是大端存储\n");
	}

	return 0;
}

下面我们来封装函数进行改进:

int check_sys()
{
	int a = 1;
	char* p = (char*)&a;
	if (*p == 1)
		return 1;
	else
		return 0;//后面几步可直接写成return *(char*)&a;

}

int main()
{
	//写一段代码告诉我们当前机器字节序是什么
	//返回1,小端
	//返回0,大端
	int ret = check_sys();
	if (ret == 1)
	{
		printf("这是小端存储\n");
	}
	else
	{
		printf("这是大端存储\n");
	}
	return 0;
}


​ END TODAY

posted @ 2021-05-29 15:40  小阿宇  阅读(65)  评论(0)    收藏  举报