Puedo "C" - almacenamiento de datos

 Tabla de contenido

  

1. Introducción a los tipos de datos

1.1 Clasificación básica de tipos:

2. La forma se almacena en la memoria. 

2.1 Código original, código inverso, código complementario

2.2 Introducción al endian grande y pequeño

2.3 Ejercicios  

3. Almacenamiento de tipos de punto flotante en la memoria. 

3.1 Un ejemplo  

3.2 Reglas de almacenamiento de números de punto flotante  


1. Introducción al tipo de datos

char         // tipo de datos de carácter
corto       // entero corto
int         // dando forma
largo         // entero largo
largo largo   // forma más larga
float       // número de punto flotante de precisión simple
doble       // número de punto flotante de doble precisión
// ¿ Existe un tipo de cadena en lenguaje C ?
El significado del tipo:
1. Utilice este tipo para abrir el tamaño del espacio de memoria (el tamaño determina el alcance de uso).
2. Cómo mirar la perspectiva del espacio de la memoria.

1.1 Clasificación básica de tipos:

Familia de plásticos:
carbonizarse
        char unsigned //sólo poner números positivos
        carácter firmado //poner números positivos y negativos
// Los valores ASCII se utilizan esencialmente al almacenar y representar caracteres. Los valores ASCII son números enteros y los tipos de caracteres también se clasifican en familias de números enteros.
El int que usamos habitualmente es equivalente al int firmado, y se puede omitir el signo.
corto
        corto sin firmar [ int ]
        firmado corto [ int ]
En t
        entero sin firmar
        firmado entero
largo
        largo sin firmar [ int ]
        firmado largo [ int ]

 Familia de coma flotante:

flotar
doble

Tipo construido (tipo personalizado):

> tipo de matriz
> tipo de estructura estructura
> enumeración tipo enumeración
> unión tipo unión

 tipo de puntero

int* pi ;
carbón * ordenador personal ;
flotar* pf ;
vacío* pv ;

tipo vacío: 

void representa un tipo vacío (sin tipo)
Generalmente se aplica al tipo de retorno de la función, al parámetro de la función, al tipo de puntero.
void test(...)//La función no necesita devolver un valor
{}
prueba nula (void) // La función no requiere parámetros
{}
void* p;//Sin puntero de tipo específico

2. Almacenamiento de modelado en la memoria. 

Dijimos antes que la creación de una variable es para abrir espacio en la memoria. El tamaño del espacio se determina según diferentes tipos. Entonces, hablemos de cómo se almacenan los datos en la memoria asignada. 

Por ejemplo: 

int a = 20 ;
int b = - 10 ;
Sabemos que se asignan cuatro bytes de espacio para un archivo .
¿Cómo almacenarlo?
Baja y comprende los siguientes conceptos:

2.1 Código original, código inverso, código complementario

Hay tres métodos de representación binaria de números enteros en las computadoras : código original, código complementario y código complementario.
Los tres métodos de representación tienen dos partes, bit de signo y bit de valor . El bit de signo usa 0 para representar " positivo " , 1 para representar " negativo " y el bit de valor.
El original, inverso y complemento de los números positivos son iguales.
Hay tres formas diferentes de representar números enteros negativos.
código original
El código original se puede obtener traduciendo directamente el valor al binario en forma de números positivos y negativos.
código inverso
Mantenga el bit de signo del código original sin cambios e invierta los otros bits uno por uno para obtener el código inverso.
Complementar
El código inverso + 1 obtendrá el código complementario.

Para dar forma: los datos almacenados en la memoria son en realidad el código complementario.

¿por qué?

En los sistemas informáticos, los valores siempre se expresan y almacenan en complemento a dos. La razón es que, usando el código de complemento, el bit de signo y el campo de valor se pueden procesar de manera uniforme, al mismo tiempo, la suma y la resta también se pueden procesar de manera uniforme (la CPU solo tiene un sumador). Además, el proceso de operación El código del complemento y el código original son iguales, no se requieren circuitos de hardware adicionales.

Veamos el almacenamiento en la memoria:

Podemos ver que los complementos se almacenan para a y b respectivamente. Pero descubrimos que el orden estaba un poco fuera de lugar .
¿Por qué? Esto involucra extremos grandes y pequeños nuevamente, mira hacia abajo ~

2.2 Introducción al endian grande y pequeño

 Qué big endian, little endian:

El modo big-endian (almacenamiento) significa que los bits bajos de los datos se almacenan en las direcciones altas de la memoria, mientras que los bits altos de los datos se almacenan en las direcciones bajas de la memoria.
medio;
El modo little-endian (almacenamiento) significa que los bits bajos de datos se almacenan en las direcciones bajas de la memoria, mientras que los bits altos de datos se almacenan en los lugares altos de la memoria.
DIRECCIÓN.

 

 

Por qué existe big endian y little endian:

¿Por qué hay una diferencia entre los modos endian grandes y pequeños? Esto se debe a que en el sistema informático utilizamos bytes como unidad, y cada unidad de dirección corresponde a un byte, y un byte tiene 8 bits . Pero en el lenguaje C , además del char de 8 bits , también hay tipos cortos de 16 bits y tipos largos de 32 bits (dependiendo del compilador específico), además, para procesadores con más de 8 bits, como 16 bits O para un procesador de 32 bits, dado que el ancho del registro es mayor que un byte, debe haber un problema de cómo organizar varios bytes. Por lo tanto, conduce al modo de almacenamiento big-endian y al modo de almacenamiento little-endian.
Por ejemplo: un tipo corto de 16 bits x , la dirección en la memoria es 0x0010 , el valor de x es 0x1122 , luego 0x11 es el byte alto y 0x22 es el byte bajo. Para el modo big-endian, coloque 0x11 en la dirección baja, es decir, 0x0010 , y coloque 0x22 en la dirección alta, es decir, 0x0011 . Modo little endian, todo lo contrario. Nuestra estructura X86 comúnmente utilizada es el modo little-endian, mientras que KEIL C51 es el modo big-endian. Muchos ARM y DSP están en modo little-endian. Algunos procesadores ARM también pueden elegir el modo big-endian o el modo little-endian por hardware.

 Preguntas de la prueba escrita para ingenieros de sistemas de Baidu 2015 :

Describa brevemente los conceptos de big-endian y little-endian y diseñe un pequeño programa para determinar el orden de bytes de la máquina actual. ( 10 puntos)
// código 1
#incluir <stdio.h>
int check_sys ()
{
int yo = 1 ;
retorno ( * ( char * ) & i );
}
int principal ()
{
int ret = check_sys ();
si ( ret == 1 )
{
printf ( " little endian \n" );
}
demás
{
printf ( " big endian \n" );
}
devolver 0 ;
}
// Código 2
int check_sys ()
{
Unión
{
int yo ;
carácter c ;
} y ;
un . i = 1 ;
volver ONU . c ;
}

2.3 Ejercicios 

1.
// ¿ generar qué?
#incluir <stdio.h>
int principal ()
{
    carácter a = - 1 ;
//100000000000000000000000000000001
//111111111111111111111111111111110
//11111111111111111111111111111111
//11111111 - truncado
//Promoción de enteros - promoción según el bit de signo
//11111111111111111111111111111111
//1111111111111111111111111111110 - menos 1
//100000000000000000000000000000001
    carácter firmado b = - 1 ;
    carácter sin firmar c =- 1 ;
//10000000000000000000000000000001
//111111111111111111111111111111110
//11111111111111111111111111111111
//11111111 - Si es un número sin signo, suma directamente 0 al bit alto
//00000000000000000000000011111111 se convierte a 255 en decimal
// El bit de signo del bit más alto después de completar 0 es 0, por lo que los códigos original, inverso y complemento son los mismos
    printf ( "a=%d,b=%d,c=%d" , a , b , c );
    devolver 0 ;
}

La estructura es a = -1 b = -1 c = 255

 

 

 

¿Qué genera el siguiente programa?

2.
#incluir <stdio.h>
int principal ()
{
    carácter a = - 128 ;
    printf ( "%u\n" , a );
    devolver 0 ;
}

//10000000000000000000000010000000 - código original

//1111111111111111111111101111111 - inversa

//1111111111111111111111110000000 - complemento

//10000000 - un truncamiento

——> Complemento de refuerzo entero 1

//11111111111111111111111110000000

//%u print piensa que el complemento impreso es el mismo que el complemento invertido original para números sin signo

Así, la impresión directa (convertida a decimal) imprime más de 4.200 millones

3.
#incluir <stdio.h>
int principal ()
{
    carácter a = 128 ;
    printf ( "%u\n" , a );
    devolver 0 ;
}

 Es exactamente igual que el último, porque el truncamiento es lo mismo que llenar 1

4.
int yo = - 20 ;
  int   sin signo j = 10 ;
printf ( "%d\n" , i + j );
// Operar en forma de complemento a dos y finalmente formatearlo como un entero con signo
Explicación detallada:
//10000000 00000000 00000000 00010100 El código original del negativo 20
//11111111 11111111 11111111 11101011 El código negativo del negativo 20 (el bit de signo permanece sin cambios y los demás se invierten) //11111111 11111111 1111111 1 11101100 Complemento a 20 negativo (suma
1 al complemento para obtener el código del complemento)
//00000000 00000000 00000000 00001010 El código original de 10 (el original, el inverso y el complemento de los números positivos son iguales) //11111111 11111111
11111111 11110110 La suma de -20 y el complemento a 10
/ / (el resultado de la computadora se almacena en la memoria. Es el código complementario)
//11111111 11111111 11111111 11110101 (menos 1)
//10000000 00000000 00000000 00001010 (inverso) para obtener -10
5.
int sin firmar yo ;
para ( yo = 9 ; yo >= 0 ; yo - )
{
    printf ( "%u\n" , i );
}

//-1 del suplemento original
// 100000000000000000000000000000000001 Original
// 1111111111111111111111111111111110 Anti-anti
// 11111111111111111111111111111 llenar
// Cuando el ciclo I-0, la reducción es -1 nuevamente, y -1 de -1 El suplemento es 1111111111111111111111111111111111, a oportunidad informática Piensa que es un número muy grande, por lo que sigue repitiendo.

 %u imprime un número sin firmar

Pero si cambio a %d, puedo imprimir -1

6.
int principal ()
{
    carácter a [ 1000 ];
    int yo ;
    para ( yo = 0 ; yo < 1000 ; yo ++ )
  {
        a [ yo ] = -1 - yo ;
  }
    printf ( "%d" , strlen ( a ));
    devolver 0 ;
}
    //-1 -2 -3 -4...-127...-998 -999 -1000
    //char -1 -2 -3...-128 127 126...3 2 1...0 -1 -2...-128 127
// strlen encuentra la longitud de la cadena y busca \0. El valor del código ASCII de \0 es 0, por lo que el cálculo de la longitud de char se detendrá cuando llegue a 0, por lo que 128+127=255
El resultado imprimirá 225
El rango de valores del tipo char es -128~127

7.
#incluir <stdio.h>
carácter sin firmar i = 0 ;
//0~255
int principal ()
{
    para ( yo = 0 ; yo <= 255 ; yo ++ )
  {
        printf ( "hola mundo\n" );
//La conversión de 256 en decimal a binario es 1 00000000. Los siguientes ocho dígitos no se convierten en 0, por lo que la condición de i<=255 siempre es verdadera, por lo que el bucle infinito
  }
    devolver 0 ;
}
Entonces el resultado es un bucle infinito que imprime hola mundo.

3. Almacenamiento de punto flotante en la memoria 

Números de coma flotante comunes:

3.14159
1E10
La familia de coma flotante incluye: tipos flotante , doble y doble largo .
El rango de números de punto flotante: definido en float.h

3.1 Un ejemplo 

Ejemplo de almacenamiento de punto flotante:
int principal ()
{
int norte = 9 ;
flotador * pFloat = ( flotante * ) & n ;
printf ( "El valor de n es: %d\n" , n );
printf ( "El valor de *pFloat es: %f\n" , * pFloat );
* pFlotación = 9,0 ;
printf ( "El valor de num es: %d\n" , n );
printf ( "El valor de *pFloat es: %f\n" , * pFloat );
devolver 0 ;
}

El valor de n es: 9 --> se imprime en forma de número entero

El valor de *pFloat es: 0.000000 --> el resultado obtenido en forma de número de punto flotante no es 9.0, lo que indica que la forma de almacenamiento de un número entero es diferente a la del número de punto flotante

Las dos similitudes siguientes verifican nuevamente que la forma de almacenamiento de números enteros y números de punto flotante son diferentes.

¿Cuál es el resultado de la salida?

3.2 Reglas de almacenamiento de números de punto flotante 

num y *pFloat son obviamente el mismo número en la memoria, ¿por qué hay una diferencia tan grande entre los resultados de interpretación de los números de punto flotante y los enteros?
Para comprender este resultado, debe comprender cómo se representan los números de punto flotante dentro de la computadora.
Interpretación detallada:
Según el estándar internacional IEEE (Instituto de Ingeniería Eléctrica y Electrónica) 754 , cualquier número binario de coma flotante V se puede expresar de la siguiente forma:
  • (-1)^S*M*2^E
  • (-1)^S representa el bit de signo, cuando S=0 , V es un número positivo; cuando S=1 , V es un número negativo.
  • M representa un número válido, mayor o igual a 1 y menor que 2 .
  • 2^E significa bits exponentes.
  • Ejemplo: 5.5 en forma binaria  -->

Como se muestra en el principio 5.5, convierta a 101.1 notación científica 1.011*2^2

 

Por ejemplo:
5,0 en decimal es 101,0 en binario , lo que equivale a 1,01×2^2 .
Luego, de acuerdo con el formato de V anterior , se puede concluir que S=0 , M=1.01 y E=2 .
El decimal -5.0 se escribe como -101.0 en binario , lo que equivale a -1.01 × 2^2 . Entonces, S=1 , M=1,01 , E=2 .
IEEE 754 establece:
Para números de punto flotante de 32 bits, el bit más alto es el bit de signo s , los siguientes 8 bits son el exponente E y los 23 bits restantes son el número efectivo M.

Para números de punto flotante de 64 bits, el bit más alto es el bit de signo, los siguientes 11 bits son el exponente E y los 23 bits restantes son el significado M.

IEEE 754 tiene algunas regulaciones especiales sobre el número significativo M y el exponente E.
Como se mencionó anteriormente, 1≤M<2 , es decir, M se puede escribir en la forma 1.xxxxxx , donde xxxxxx representa la parte decimal.
IEEE 754 estipula que cuando M se guarda dentro de la computadora , el primer dígito de este número siempre es 1 por defecto , por lo que se puede descartar y solo se guarda la parte xxxxxx que sigue.
Por ejemplo, al guardar 1.01 , solo guarde 01 y luego agregue el primer 1 al leer. El propósito de hacer esto es ahorrar 1 cifra significativa. Tome el número de punto flotante de 32 bits como ejemplo, solo quedan 23 bits para M , y después de descartar el primer 1, equivale a guardar 24 cifras significativas.
En cuanto al índice E , la situación es más complicada. Abajo
Primero, E es un entero sin signo ( unsigned int )
Eso significa que si E tiene 8 bits, su rango de valores es 0~255 ; si E tiene 11 bits, su rango de valores es 0~2047 . Sin embargo, sabemos que E en notación científica puede tener números negativos, por lo que IEEE 754 estipula que se debe sumar un número intermedio al valor real de E cuando se almacena en la memoria . Para E de 8 bits , este número intermedio es 127 ; para E de 11 bits , este número intermedio es 1023 . Por ejemplo, la E de 2^10 es 10 , por lo que al guardarlo como un número de punto flotante de 32 bits, se debe guardar como 10+127=137 , es decir, 10001001.
Luego, el índice E se recupera de la memoria y se puede dividir en tres casos:
E no es todo 0 o no todo 1
En este momento, el número de coma flotante está representado por las siguientes reglas, es decir, al valor calculado del exponente E se le resta 127 (o 1023 ) para obtener el valor real, y luego el
Agregue el primer dígito 1 antes del dígito significativo M.
Por ejemplo:
La forma binaria de 0.5 ( 1/2 ) es 0.1 , ya que se estipula que la parte positiva debe ser 1 , es decir, se desplaza la coma decimal 1 hacia la derecha , entonces es
1.0*2^(-1) , su código de pedido es -1+127=126 , expresado como
01111110 , y la mantisa 1.0 elimina la parte entera para que sea 0 , llena de 0 a 23 dígitos 00000000000000000000000 , luego es binario
La forma de representación es :

 0 01111110 000000000000000000000000

E es todo 0

En este momento, el exponente E del número de coma flotante es igual a 1-127 (o 1-1023 ), que es el valor real.
El número significativo M ya no suma el primer 1 , sino que restablece el decimal 0.xxxxxx . Esto se hace para representar ±0 , así como cerca de
0 es un número muy pequeño.

 E es todo 1

En este momento, si el dígito significativo M es todo 0 , significa ± infinito (positivo o negativo depende del bit de signo s );

Bueno, eso es todo en cuanto a las reglas de representación de números de coma flotante.

Para explicar la pregunta anterior:

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

A continuación, volvamos a la pregunta original: ¿Por qué 0x00000009 se convierte en 0,000000 cuando se restaura a un número de punto flotante ?
Primero, divida 0x00000009 para obtener el primer bit de signo s=0 y el exponente de los siguientes 8 bits E=00000000 .
Los últimos 23 dígitos significativos M=000 0000 0000 0000 0000 1001 .

9 -> 0000 0000 0000 0000 0000 0000 0000 1001 

Dado que el exponente E es todo 0 , cumple con el segundo caso de la sección anterior. Por tanto, el número de coma flotante V se escribe como:

  V=( - 1)^0 × 0,00000000000000000001001×2^( - 126)=1,001×2^( - 146) 

Obviamente, V es un número positivo muy pequeño cercano a 0 , por lo que es 0,000000 en notación decimal . 

Mire la segunda parte del ejemplo.

¿Puedo preguntarle al número de coma flotante 9.0 cómo usar la representación binaria? ¿Qué es la reducción a decimal?
Primero, el número de coma flotante 9,0 es igual a 1001,0 en binario , que es 1,001×2^3 .
9.0 -> 1001.0 -> ( -1 ) ^ 01 . 0012 ^3 -> s = 0 , M = 1.001 , E = 3 + 127 = 130
Entonces, el primer bit de signo s=0 , el número efectivo M es igual a 001 seguido de 20 ceros , formando 23 bits, y el exponente E es igual a 3+127=130 ,
Eso es 10000010 .
Por lo tanto, escrito en forma binaria, debería ser s+E+M , es decir
0 10000010 001 0000 0000 0000 0000 0000

Este número binario de 32 bits, restaurado a decimal, es exactamente 1091567616 . 

EL FIN

        Esto es algo que compartimos hoy sobre el almacenamiento de datos. ¡Espero que pueda ayudar a todos! Si hay alguna deficiencia, por favor, los miembros de la familia le dan a Xiaoye algunas buenas sugerencias. ¡Continuaré optimizando el artículo! ¡Entonces trabajemos juntos! Jajajajaja

 

 

 

Supongo que te gusta

Origin blog.csdn.net/Yzl17841857589/article/details/130050024
Recomendado
Clasificación