[Langage C] Explication détaillée du stockage des données en mémoire

1. Qu'est-ce qu'un type de données

Nous pouvons considérer le type de données comme une boîte rectangulaire. Des types tels que int et char sont différentes boîtes qui peuvent stocker des choses (données) de différentes tailles (c'est-à-dire la taille de l'espace de stockage). La signification du type : use ce type pour ouvrir
la
mémoire La taille de l'espace (la taille détermine la portée d'utilisation)
comment regarder la perspective de l'espace mémoire.

Deuxièmement, la classification de base des types

insérez la description de l'image ici
Avis:
Le caractère est stocké dans la mémoire en tant que valeur de code ASCII du caractère, et la valeur de code ASCII est un nombre entier, de sorte que le caractère est classé dans la famille des nombres entiers.
Que char soit signé char ou non n'est pas stipulé par la norme du langage C, cela dépend du compilateur.

3. Stockage des nombres entiers en mémoire

La création d'une variable consiste à libérer de l'espace en mémoire. La taille de l'espace est déterminée en fonction de différents types.
Voyons ensuite comment les données sont stockées dans l'espace ouvert en mémoire.

1. Code original, code inverse, code complémentaire

Tout d'abord, il faut savoir qu'il existe trois modes .code inverse et code complément,originaldans les ordinateursnombres entiers
de représentation

  • L'original, l'inverse et le complément des entiers positifs sont les mêmes
  • Les trois représentations des entiers négatifs sont différentes
    • Le code d'origine peut traduire directement le binaire en binaire sous la forme de nombres positifs et négatifs
    • Le code inverse conserve le bit de signe du code d'origine inchangé, et les autres bits peuvent être obtenus en inversant les autres bits à leur tour.
    • Code complément inverse + 1 pour obtenir le code complément
      Avispour les entiersLes données stockées dans la mémoire sont en fait stockées en code complémentaire
      La raison en est que dans les systèmes informatiques, les valeurs sont toujours représentées et stockées en code complémentaire. La raison en est qu'en utilisant le code complémentaire, le bit de signe et le champ de valeur peuvent être traités de manière uniforme. Dans le même temps, l'addition et la soustraction peuvent également être traitées de manière unifiée (le processeur n'a qu'un additionneur).De plus, le code complémentaire et le code d'origine sont convertis l'un à l'autre, et le processus de fonctionnement est le même, et aucun circuit matériel supplémentaire n'est requis.

2. Gros et petit boutiens

(1) Qu'est-ce que le gros et le petit endian ?

prémisse:
insérez la description de l'image ici

L'ordre des octets endian fait référence à l'ordre des octets dans lequel les données sont stockées sur l'ordinateur

  • Mode big-endian (stockage), ce qui signifie que les bits de poids faible des données sont stockés à l'adresse haute de la mémoire , et les bits de poids fort des données sont stockés à l'adresse basse de la mémoire
    insérez la description de l'image ici

  • Mode Little Endian (stockage), ce qui signifie que les bits de poids faible des données sont stockés dans les adresses basses de la mémoire et les bits de poids fort des données sont stockés dans les adresses hautes de la mémoireMémoriser( low low high high )
    insérez la description de l'image ici
    Parmi eux, dans VS2022, c'est le mode little endian utilisé
    insérez la description de l'image ici

(2) Pourquoi y a-t-il des gros et des petits bouts

Car dans le système informatique, chaque unité d'adresse correspond à un octet, et un octet vaut 8 bits. Mais dans le langage C, en plus du caractère 8 bits, il existe également des types courts 16 bits et des types longs 32 bits (selon le compilateur spécifique).De plus, pour les processeurs de plus de 8 bits, tels que 16 bits Ou un processeur 32 bits, puisque la largeur du registre est supérieure à un octet, il doit y avoir un problème d'organisation de plusieurs octets. Par conséquent, cela conduit au mode de stockage big-endian et au mode de stockage little-endian.
[Exemple] Un type court de 16 bits x, l'adresse dans la mémoire est 0x0010 et la valeur de x est 0x1122, puis 0x11 est l'
octet de poids fort et 0x22 est l'octet de poids faible. Pour le mode big-endian, mettez 0x11 dans l'adresse basse, c'est-à-dire 0x0010, et mettez 0x22 dans l'adresse haute, c'est-à-dire 0x0011. Le mode little endian, c'est tout le contraire. Notre structure X86 couramment utilisée est en mode petit-boutiste, tandis que KEILC51 est en mode gros-boutiste. De nombreux ARMDSP sont little-endian. Certains processeurs ARM peuvent également choisir le mode big-endian ou le mode little-endian par le matériel
[questions de test écrites par l'ingénieur système]

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

insérez la description de l'image ici

#include<stdio.h>
int check_sys() 
{
    
    
	int a = 1;
	char* p = (char*) & a;//拿到一个字节地址

	if (*p == 1)
		return 1;
	else
		return 0;

	//可以有优化 return *( (char*)&a ); 
}
int main() 
{
    
    
	if (check_sys())
		printf("小端\n");
	else
		printf("大端\n");

	return 0;
}

4. Stockage des types à virgule flottante en mémoire

Nombres à virgule flottante courants :

  • 3.141592
  • 1E10 Ce E équivaut à la notation scientifique exponentielle 1 * 10^10 1 fois 10 à la puissance 10.
    La famille des nombres à virgule flottante comprend les types float, double, long double.
    La plage de nombres à virgule flottante (détaillée ci-dessous) : (Dans vs, #include<float.h> Allez à la définition pour voir) Peu importe si les images suivantes sont difficiles à comprendre
    insérez la description de l'image ici

1. Règles de stockage des nombres à virgule flottante

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

  • (-1)^S * M * 2^E
  • (-1)^s représente le bit de signe, lorsque s=0, V est un nombre positif ; lorsque s=1, V est un nombre négatif.
  • M représente un nombre valide, supérieur ou égal à 1 et inférieur à 2.
  • 2^E signifie bit d'exposant

[Exemple] Système décimal : 9.0 est écrit sous la forme binaire 1001.0 et réécrit sous la forme 1.001* 2^3 à (-1) ^0 * 1.001 * 2 ^ 3. S = 0, M = 1,001, E = 3.
La norme IEEE fournit deux formats principaux pour les nombres à virgule flottante : simple précision (32 bits) et double précision (64 bits) . Divisé en trois sections : signe, exposant et décimal . La partie exposant détermine la plage du nombre à virgule flottante. Le nombre de chiffres dans la partie fractionnaire détermine la précision. (Voir ci-dessous)

Pour les nombres à virgule flottante de 32 bits, le 1 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 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.
insérez la description de l'image ici
AvisIEEE754 a d'autres réglementations sur le nombre significatif M et l'exposant E

1≤M<2, c'est-à-dire que M peut s'écrire sous la forme 1.xxxxxx, où xxxxxx représente la partie fractionnaire.
Nombre significatif M
IEEE 754 stipule que lorsque M est enregistré dans l'ordinateur, le premier chiffre de ce nombre est toujours 1 par défaut, il peut donc être ignoré, et seule la partie xxxxxx qui suit est enregistrée. Par exemple, lors de l'enregistrement de 1.01, enregistrez uniquement 01 , puis ajoutez le premier 1 lors de la lecture. Le but est d'économiser 1 chiffre significatif. En prenant le nombre à virgule flottante 32 bits comme exemple, il ne reste plus que 23 bits pour M. Une fois le premier 1 supprimé, cela équivaut à enregistrer 24 chiffres significatifs.
L'exposant E
E est un entier non signé, si E est de 8 bits (0~255), E est de 11 bits (0~2047). Et parce que E dans la méthode de notation scientifique peut avoir des nombres négatifs, IEEE 754 stipule que lors du stockage de la valeur réelle de E dans la mémoire, un nombre intermédiaire doit être ajouté. Pour E à 8 chiffres, le nombre intermédiaire est 127 ; pour 11- chiffre E, le nombre du milieu est 1023. [Par exemple], le E de 2^10 est 10, donc lors de son enregistrement en tant que nombre à virgule flottante 32 bits, il doit être enregistré sous 10+127=137, c'est-à-dire 10001001.
prochaine discussion

  • Quand E est tout 1 , quand M est tout 0, cela signifie l'infini (positif ou négatif dépend du bit de signe S)
  • Lorsque E est tout 0 , le nombre effectif M ne s'additionnera plus au premier 1, mais sera réduit à une décimale de 0.xxxxxx. Ceci est fait pour représenter ± 0 et
    de très petits nombres proches de 0.
  • Lorsque E n'est pas tout à 0 et 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
    premier chiffre est ajouté avant le nombre effectif M 1. La forme binaire de 0,5 (1/2) est 0,1. Puisque la partie positive doit être 1, c'est-à-dire que le point décimal est déplacé vers la droite de 1 bit , c'est 1.0*2^(-1), et son code d'ordre est -1+127 =126, exprimé comme 01111110, et la mantisse 1.0 supprime la partie entière pour être 0, remplit 0 à 23 chiffres 00000000000000000000000, puis son binaire la représentation est : 0 01111110 00000000000000000000000

5. Pratique

Que produit le code suivant ?

1.

#include<stdio.h>
int main() 
{
    
    
	char a = -1;
	signed char b = -1;
	unsigned char c = -1;
	printf("a=%d,b=%d,c=%d\n",a,b,c);
	return 0;
}

[Résultat] a=-1, b=-1, c=255
analyser
insérez la description de l'image ici

2.

#include<stdio.h>

int main() 
{
    
    
	char a = -128;
	printf("%u\n",a);
	return 0;
}

【Résultat】4294967168
analyser
insérez la description de l'image ici

3.

#include<stdio.h>

int main() 
{
    
    
	char a = 128;
	printf("%u\n",a);
	return 0;
}

【Résultat】4294967168
analyser
insérez la description de l'image ici

4.

#include<stdio.h>

int main() 
{
    
    
	int i = -20;
	unsigned int j = 10;
	printf("%d\n",i+j);
	return 0;
}

【Résultat】-10
analyser
Opérer sous la forme d'un complément à deux, et enfin le formater en un entier signé
insérez la description de l'image ici

5.

#include<stdio.h>
int main() 
{
    
    
	unsigned int i;
	for (i = 9; i >= 0;i--)
	{
    
    
		printf("%u\n",i);
	}
	return 0;
}

[Résultat] Boucle infinie
analyser
unsigned int (range 0~4294967295) ne peut jamais être inférieur à 0
La condition de jugement de la boucle for est i >= 0

6.

int main() 
{
    
    
	char a[1000];
	int i;
	for (i = 0; i < 1000;i++)
	{
    
    
		a[i] = -1 - i;
	}
	printf("%d",strlen(a));
	return 0;
}

【Résultat】255
analyser
insérez la description de l'image ici

7.

#include<stdio.h>
unsigned char i = 0;
int main() 
{
    
    
	for (i = 0; i <= 255;i++)
	{
    
    
		printf("hello world\n");
	}
	return 0;
}

[Résultat] Impression en boucle infinie hello world
analyser
La plage de caractères non signés est comprise entre 0 et 255, donc la plage de valeurs de i ne peut pas être supérieure à 255, et la partie de jugement de la boucle for ne s'arrêtera pas

Je suppose que tu aimes

Origine blog.csdn.net/qq_72505850/article/details/132129359
conseillé
Classement