Sauveur de langage C avancé (stockage de données en mémoire--9)

teneur

1.1 Introduction aux types de données

1.2 Classification de base des types

2.1 Stockage des formes en mémoire

2.2 Code original, code inverse, code complément

2.3 Stockage Big et Small Endian (triés par octets)

Questions du test écrit de l'ingénieur système Baidu 2015 :

2.4 Les caractères signés et non signés sont stockés en mémoire

2.5 Que se passe-t-il lorsque vous mettez des nombres négatifs dans des entiers non signés

3.1 Exercice

4.1 Stockage en virgule flottante en mémoire

4.2 Règles de stockage en virgule flottante 

Les nombres à virgule flottante peuvent perdre en précision et ne peuvent pas être stockés avec précision

L'index E est extrait de la mémoire et peut être divisé en trois cas :


 

1.1 Introduction aux types de données

carboniser type de données de caractère
court         Entier court
entier Entier
longue Entier long, en langage C, long>=int
longtemps longtemps mise en forme plus longue
flotter nombre à virgule flottante simple précision
double nombre à virgule flottante double précision

 

Signification du type :

1. Utilisez ce type pour ouvrir la taille de l'espace mémoire (la taille détermine la plage d'utilisation)

2. Comment regarder la perspective de l'espace mémoire.

1.2 Classification de base des types

1.整形家族


char//虽然是字符类型,但是字符类型存储的时候存放的是字符的ASCII码值,是整数 
    //C语言没定义char是否为有符号还是无符号,取决于编译器

 unsigned char
 signed char

short //默认为有符号
 unsigned short [int]
 signed short [int]

int //默认为有符号
 unsigned int
 signed int

long  //默认为有符号
 unsigned long [int]
 signed long [int]



2.浮点数家族

float  //默认为有符号
double  //默认为有符号


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

> 数组类型
> 结构体类型 struct
> 枚举类型 enum
> 联合类型 union



4.指针类型
int *pi;
char *pc;
float* pf;
void* pv;//空类型:void 表示空类型(无类型)通常应用于函数的返回类型、函数的参数、指针类型。

Température : (-5 10) a des données positives et négatives et peut être stockée dans une variable signée

Âge (uniquement des nombres positifs) Seuls des nombres positifs peuvent être placés dans des variables non signées


2.1 Stockage des formes en mémoire

2.2 Code original, code inverse, code complément

Il existe trois méthodes de représentation des nombres entiers dans l'ordinateur, à savoir le code original, le code inverse et le code complémentaire.

Les trois méthodes de représentation comportent deux parties : le bit de signe et le bit de valeur.Le bit de signe vaut 0 pour "positif" et 1 pour "négatif".

Les trois représentations des entiers négatifs varient.

L'original, l'inverse et le complément des nombres positifs sont les mêmes. Pour la mise en forme : les données stockées dans la mémoire stockent en fait le code complément.

//整数可以写出三种2进制表示形式:
//原码:直接将数值按照正负数的形式翻译成二进制就可以
//反码:将原码的符号位不变,其他位依次按位取反就可以得到了
//补码:反码+1就得到补码。

int main()
{
	int a = 10;//整型值
	//原码:00000000000000000000000000001010
	//反码:00000000000000000000000000001010
	//补码:00000000000000000000000000001010

	int b = -10;//整型值
	//原码:10000000000000000000000000001010
	//反码:11111111111111111111111111110101
	//补码:1111 1111 1111 1111 1111 1111 1111 0110
	//      F    F    F     F   F     F    F   6
	在内存中存放的十六进制为是:0xff ff ff f6吗?
	//
	return 0;
}


//正整数的原码、反码、补码相同
//负数的原码、反码、补码是需要计算的

On peut voir que les données b sont stockées dans la mémoire sous la forme F6 FF FF FF, qui est stockée à l'envers, car les grandes et les petites extrémités

int main()
{
	int a = 0x11223344;

	return 0;
}

 

2.3 Stockage Big et Small Endian (triés par octets)

Le mode d'ordre des octets big-endian (stockage) signifie que les bits de poids faible des données sont stockés à l'adresse haute de la mémoire et que les bits de poids fort des données sont stockés à l'adresse basse de la mémoire ;

Le mode Little-endian (stockage) signifie que les bits de poids faible des données sont stockés à l'adresse basse de la mémoire , et les bits de poids fort des données sont stockés à l'adresse haute de la mémoire.

int main()
{
	int a = 0x11223344;

	return 0;
}

 Pourquoi y a-t-il des modes big et small endian ? En effet, dans les systèmes informatiques, nous utilisons les octets comme une unité, chaque unité d'adresse correspond à un octet et un octet est de 8 bits. Mais il existe également des types courts 16 bits et des types longs 32 bits. De plus, pour les processeurs de plus de 8 bits, tels que les processeurs 16 bits ou 32 bits, étant donné que la largeur de registre est supérieure à un octet, il doit être un La question de savoir comment organiser plusieurs octets

 

Questions du test écrit de l'ingénieur système Baidu 2015 :

Veuillez décrire brièvement les concepts d'ordre des octets gros-boutiste et d'ordre des octets petit-boutiste, et concevoir un petit programme pour déterminer l'ordre des octets de la machine actuelle.

思路:例如刚刚的0x11223344,我们只需要判断第一个字节是不是11即可

//00000000000000000000000000000001
//0x 00 00 00 01


int check_sys()
{
	int a = 1;
	char* p = (char*)&a;//向后访问一个字节
	return *p;
}

//int check_sys()//第二种写法
//{
//	int a = 1;
//	return *(char*)&a;
//}

int main()
{
	int ret = check_sys();
	if (ret == 1)
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}

2.4 Les caractères signés et non signés sont stockés en mémoire

Valeur signée -128~127

Valeur non signée 0~255

Remarque : 10000000 est directement analysé comme -128 dans le bit signé


2.5 Que se passe-t-il lorsque vous mettez des nombres négatifs dans des entiers non signés


#include <stdio.h>

int main()
{
	unsigned int ch = -10;//作用1:创建变量时指定大小 
                          //作用2:这个符号数怎么被理解取决于你如何使用
	//-10
	//10000000000000000000000000001010
	//11111111111111111111111111110101
	//11111111111111111111111111110110
	
	//printf("%u\n", ch);//结果是非常大的整数   %u是打印无符号数
    //意思是你要我打印的一定是无符号数,不是无符号数,我也认为是无符号数
	

    printf("%d\n", ch);//结果是-10    %d是打印有符号数
    //11111111111111111111111111110110转换成原码
    //意思是你要我打印的一定是有符号数,不是有符号的数,我也认为是有符号数
	return 0;
}

Mettre un nombre négatif dans un entier non signé et l'imprimer de différentes manières revient en fait à laisser le compilateur fonctionner en bits binaires, et s'il y a un signe, le bit le plus élevé est compris comme le bit de signe, 1 est un nombre négatif et 0 est un entier


3.1 Exercice

//输出什么?
#include <stdio.h>
int main()
{
    char a= -1;
    signed char b=-1;
    unsigned char c=-1;
    printf("a=%d,b=%d,c=%d",a,b,c);
    return 0;
}
//输出什么?
#include <stdio.h>
int main()
{
    char a= -1;
//10000000000000000000000000000001
//11111111111111111111111111111110
//11111111111111111111111111111111
//发生截断,保留11111111 ,以%d打印,发生整型提升,最高位补符号位//11111111111111111111111111111111
 结果为-1
    signed char b=-1;
//10000000000000000000000000000001
//11111111111111111111111111111110
//11111111111111111111111111111111
//发生截断,保留11111111  以%d打印,发生整型提升,最高位补符号位//11111111111111111111111111111111
结果为-1

    unsigned char c=-1;
//10000000000000000000000000000001
//11111111111111111111111111111110
//11111111111111111111111111111111
//发生截断,保留11111111,以%d打印,整型提升,无符号数高位直接补零
//00000000000000000000000011111111
结果为255

    printf("a=%d,b=%d,c=%d",a,b,c);//a=-1 b=-1 c=255
    return 0;
}

3.2 Quelle est la sortie du programme suivant ?

#include <stdio.h>
int main()
{
    char a = -128;
    printf("%u\n",a);
    return 0;
}
#include <stdio.h>
int main()
{
    char a = -128;//~128-127
//1000000000000000000000010000000  ---128的原码
//1111111111111111111111101111111  反码
//1111111111111111111111110000000  补码
,发生截断,保留10000000
//以%u打印(无符号整数),进行整型提升,由于a是char类型,
//11111111111111111111111110000000原码
//因为按照%u进行打印,我们认为这个数字是一个正数
答案是一个很大的是数字//4,294,967,168
    printf("%u\n",a);
    return 0;
}

3.3 Quelle est la sortie du programme suivant ?

#include <stdio.h>
int main()
{
    char a = 128;
//00000000000000000000000010000000
//截断10000000
//整型提升11111111111111111111111110000000
//以%u打印,很大的正数
    printf("%u\n",a);
    return 0;
}

3.4 Quelle est la sortie du programme suivant ?

int i= -20;
unsigned  int  j = 10;
printf("%d\n", i+j); 
//按照补码的形式进行运算,最后格式化成为有符号整数

int main()
{
	int i = -20;
	//10000000000000000000000000010100
	//11111111111111111111111111101011
	//11111111111111111111111111101100 ~ -20的补码
	//
	unsigned int j = 10;
	//00000000000000000000000000001010
	//00000000000000000000000000001010
	//00000000000000000000000000001010

	printf("%d\n", i + j);//-10
	//11111111111111111111111111101100
	//00000000000000000000000000001010

	//11111111111111111111111111110110 - 相加后的结果,补码
	//11111111111111111111111111110101 - 反码
	//10000000000000000000000000001010 - 原码

    //答案是-10
	return 0;
}

3.5 Quel est le résultat de l'exécution du programme suivant ?

int main()
{
	unsigned int i;

	for (i = 9; i >= 0; i--)
	{
		printf("%u\n", i);//对一个无符号数来说,最小值是0
	}

	return 0;
}

//死循环,当i--变成-1时,11111111111111111111111111111111被理解为一个很大的数
// i==很大的数 继续循环--


3.6 Quelle est la sortie du programme suivant ?

int main()
{
    char a[1000]; 
    int i;
    for(i=0; i<1000; i++)
   {
        a[i] = -1-i;   //char取值范围~128-127
   }
    printf("%d",strlen(a));
    return 0;
}

解题思路:strlen是求字符串长度的,找的'\0'的位置,统计的\0之前出现多少个字符
'\0'的ASCII码值是0

答案是255,还记得上面画的那张char类型数据图么,逆时针循环直到遇到\0停下

4.1 Stockage en virgule flottante en mémoire

下面这题的4个结果是什么?

int main()
{
 int n = 9;
 float *pFloat = (float *)&n;
 printf("n的值为:%d\n",n);
 printf("*pFloat的值为:%f\n",*pFloat);
 *pFloat = 9.0;//找到了n
 printf("num的值为:%d\n",n);
 printf("*pFloat的值为:%f\n",*pFloat);
 return 0;
}

 

num et *pFloat sont évidemment le même nombre en mémoire, pourquoi les résultats d'interprétation des nombres à virgule flottante et des entiers sont-ils si différents ?

Pour comprendre ce résultat, vous devez comprendre comment les nombres à virgule flottante sont représentés en interne dans l'ordinateur.

n=9, mettez-le sous la forme d'un entier, et imprimez-le sous la forme d'un entier, pas de problème

*pFlottant = 0,000000 pourquoi ? Le pointeur flottant est déréférencé et les données en mémoire sont considérées comme un nombre à virgule flottante, car la méthode de stockage des nombres entiers est différente de la méthode de stockage des nombres à virgule flottante en mémoire

Le troisième *pFloat est un très grand nombre, mettez-le sous la forme d'un nombre à virgule flottante et prenez-le sous la forme d'un entier, et le résultat est différent.

4.2 Règles de stockage en virgule flottante 

Selon la norme internationale IEEE (Institute of Electrical and Electronics Engineering) 754 , tout nombre binaire à virgule flottante V peut être représenté sous la forme suivante :

(-1)^S * M * 2^E

(-1)^s représente le bit de signe. Lorsque s=0, V est positif ; lorsque s=1, V est négatif.

M représente un nombre significatif, supérieur ou égal à 1 et inférieur à 2.

2^E signifie le bit d'exposant.

Par exemple : 5,5 correspond à 101,1 en bits

 Convertir en stockage en virgule flottante

Essayons de convertir un autre nombre à virgule flottante

Les nombres à virgule flottante peuvent perdre en précision et ne peuvent pas être stockés avec précision


Comment les nombres à virgule flottante sont stockés en mémoire

Pour un nombre à virgule flottante de 32 bits, le bit le plus élevé est le bit de signe s, les 8 bits suivants sont l'exposant E et les 23 bits restants sont le significande M.

Pour un nombre à virgule flottante de 64 bits, le 1 bit le plus élevé est le bit de signe S, les 11 bits suivants sont l'exposant E et les 52 bits restants sont le significande M.

 

Comme mentionné précédemment, 1≤M<2, c'est-à-dire que M peut être écrit sous la forme 1.xxxxxx, où xxxxxx représente la partie fractionnaire.

Par défaut, le premier chiffre de ce numéro est toujours 1, il peut donc être ignoré et seule la partie xxxxxx suivante est enregistrée.

Lors de la lecture, ajoutez-y le premier 1.

Quant à l'indice E, la situation est plus compliquée.

Tout d'abord, E est un entier non signé (unsigned int) Cela signifie que si E est de 8 bits, sa plage de valeurs est de 0 à 255 ; si E est de 11 bits, sa plage de valeurs est de 0 à 2047. Cependant, nous savons que E en notation scientifique peut être négatif

Par exemple : 0.5-->(binaire)0.1 -->1.0*2^-1 ,M=1.0,E=-1

Par conséquent, IEEE 754 stipule que la valeur réelle de E doit être ajoutée à un nombre intermédiaire lorsqu'elle est stockée dans la mémoire . Pour E 8 bits, ce nombre intermédiaire est 127 ; pour E 11 bits, ce nombre intermédiaire est 1023. Par exemple, le E de 2^10 est 10, donc lorsqu'il est stocké sous forme de nombre à virgule flottante 32 bits, il doit être stocké sous la forme 10+127=137, soit 10001001.

L'index E est extrait de la mémoire et peut être divisé en trois cas :

E n'est pas tout à 0 ou pas tout à 1 À ce moment, le nombre à virgule flottante est représenté par les règles suivantes, c'est-à-dire que la valeur calculée de l'exposant E est soustraite de 127 (ou 1023) pour obtenir la valeur réelle, puis le nombre significatif M est ajouté avec le premier 1. Par exemple, E=-1 de 0,5, son code de commande est -1+127=126, qui s'exprime sous la forme 01111110,
E est tout 0 A ce moment, l'exposant E du nombre à virgule flottante est égal à 1-127 (ou 1-1023), qui est la valeur réelle, et le nombre significatif M ne s'ajoute plus au premier 1, mais est ramené à la décimale de 0.xxxxxx. Ceci est fait pour représenter ± 0 et de très petits nombres proches de 0.
E est tout 1 A ce moment, si les chiffres significatifs M sont tous 0, cela signifie ± l'infini (positif ou négatif dépend du bit de signe s)

举个例子
int main()
{
	
	float f = 5.5;
	//
	//101.1
	//(-1)^0 * 1.011 * 2^2
	//S = 0
	//E = 2   +127 = 129
	//M = 1.011
	//存储到内存:
	//0 10000001 01100000000000000000000
	//0x40b00000 
	//
	return 0;
}


Retour à notre question initiale

int main()
{
	int n = 9;
	//
	//00000000000000000000000000001001
	//0 00000000 00000000000000000001001
	//E = -126
	//M = 0.00000000000000000001001
	//S = 0
	//(-1)^0 *  0.00000000000000000001001 * 2^-126
	//1 * 0.00000000000000000001001 * 2^-126一个超级超级小的数字
	float* pFloat = (float*)&n;//int*
	printf("n的值为:%d\n", n);//9
	printf("*pFloat的值为:%f\n", *pFloat);//0.000000

	*pFloat = 9.0;
	//9.0
	//1001.0
	//1.001 * 2^3
	//(-1)^0 * 1.001 * 2^3
	//S = 0
	//M = 1.001
	//E = 3   +127
	//01000001000100000000000000000000一个很大的数字
	//
	printf("num的值为:%d\n", n);//1,091,567,616
	printf("*pFloat的值为:%f\n", *pFloat);//9.0

	return 0;
}

Je suppose que tu aimes

Origine blog.csdn.net/weixin_63543274/article/details/123791139
conseillé
Classement