Operadores de lenguaje C, promoción de plástico, truncamiento y almacenamiento de plástico en coma flotante

Operadores de lenguaje C, promoción plástica y truncamiento

Prefacio

1. Primero, debe comprender el mecanismo de almacenamiento de números enteros;
2. La relación entre el código original, el complemento a uno y el complemento a uno;
2. (1) El código original, el complemento a uno y el complemento a uno de un entero positivo son lo mismo, para que pueda realizar directamente la conversión binaria; (2 ^ 32-1 enteros positivos)
2. (2) El primer bit del entero negativo de 32 bits es el bit de signo (1 representa un número negativo); (2 ^ 31-1 signos)
Tomemos un ejemplo, por ejemplo: -1
primero Escriba el complemento de -1 como:
1000 0000 0000 0000 0000 0000 0000 0001 ----- el código original
A continuación, busque el código inverso: el bit de signo permanece sin cambios, y los otros bits se invierten para obtener el código invertido
1111 1111 1111 1111 1111 1111 1111 1110 ----- Código inverso
Finalmente, el código inverso +1 obtiene el complemento, y todos los complementos almacenados en la memoria son
1111 1111 1111 1111 1111 1111 1111 1111 1111 ----- Complemento
3. Promoción de modelado, truncamiento

parte 1. operadores bit a bit

(1) El operador AND bit a bit &: Si los dígitos binarios de las dos posiciones correspondientes son ambos 1, el resultado del bit es 1, de lo contrario, es 0. Mira el siguiente ejemplo:

    int a = 15;   //0000 0000 0000 0000 0000 0000 0000 1111 ---15的二进制表示
    int b = 19;   //0000 0000 0000 0000 0000 0000 0001 0011 ---19的二进制表示
    int c = a & b;//0000 0000 0000 0000 0000 0000 0000 0011 ---a&b=3的二进制表示

(2) Operador OR bit a bit |: Si los dígitos binarios de las dos posiciones correspondientes son ambos 0, el resultado del bit es 0; de lo contrario, es 1. Mira el siguiente ejemplo:

    int a = 15;   //0000 0000 0000 0000 0000 0000 0000 1111 ---15的二进制表示
    int b = 19;   //0000 0000 0000 0000 0000 0000 0001 0011 ---19的二进制表示
    int c = a | b;//0000 0000 0000 0000 0000 0000 0001 1111 ---a|b=31的二进制表示

(3) Operador XOR bit a bit ^: Si los bits binarios de las dos posiciones correspondientes son iguales, el resultado es 0, de lo contrario es 1. Mira el siguiente ejemplo:

    int a = 15;   //0000 0000 0000 0000 0000 0000 0000 1111 ---15的二进制表示
    int b = 19;   //0000 0000 0000 0000 0000 0000 0001 0011 ---19的二进制表示
    int c = a^b;  //0000 0000 0000 0000 0000 0000 0001 1100 ---a^b=28的二进制表示

Lo siguiente usa XOR para lograr el intercambio de dos números:

#include <stdio.h>
int main()
{
    
    
 int a = 10;  //0000 0000 0000 0000 0000 0000 0000 1010 ---10的二进制表示
 int b = 20;  //0000 0000 0000 0000 0000 0000 0001 0100 ---20的二进制表示
 a = a^b;   //a=0000 0000 0000 0000 0000 0000 0001 1110 ---30的二进制表示
 b = a^b;   //b=0000 0000 0000 0000 0000 0000 0000 1010 ---10的二进制表示
 a = a^b;   //c=0000 0000 0000 0000 0000 0000 0001 0100 ---20的二进制表示
 printf("a = %d b = %d\n", a, b);
 return 0;
}

El intercambio de dos números a través de XOR no se desbordará.
(4) Operador de cambio a la izquierda <<: regla de cambio: abandonar a la izquierda y rellenar con 0 a la derecha. Mira el siguiente ejemplo:

int main(){
    
    
    int a = 19;  //00000000000000000000000000010011
    int b = a<<1;//00000000000000000000000000100110
    printf("%d", b);//输出结果38
    return 0;
}

(5) Operador de cambio a la derecha >>:
regla de cambio: Primero, hay dos operaciones de cambio a la derecha:

  1. El desplazamiento lógico se rellena con 0 a la izquierda y se descarta a la derecha
  2. El lado izquierdo del desplazamiento aritmético se rellena con el bit de signo del valor original y el lado derecho se descarta.

Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
(6) Operador de negación bit a bit ~: Para el bit binario del número, si el bit es 1, el resultado es 0, y si se cambia a 0, el resultado es 1. P.ej:

    int a = 19;//00000000000000000000000000010011
    int b = ~a;//11111111111111111111111111101100(内存中的补码)
               //11111111111111111111111111101011(反码,即补码-1)
               //10000000000000000000000000010100(原码,即反码符号位不变,其余位数取反)

parte 2. Levantamiento y truncamiento de plástico

Las operaciones aritméticas de enteros de C siempre se realizan al menos con la precisión del tipo de entero predeterminado.
Para obtener esta precisión, los caracteres y los operandos enteros cortos de la expresión se convierten en enteros ordinarios antes de su uso, conversión que se denomina promoción integral.

//负数的整形提升
char c1 = -1;
变量c1的二进制位(补码)中只有8个比特位:
1111111
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为1
提升之后的结果是:
1111 1111  1111  1111  1111  1111  1111  1111

//正数的整形提升
char c2 = 1;
变量c2的二进制位(补码)中只有8个比特位:
00000001
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为0
提升之后的结果是:
0000 0000 0000 0000 0000 0000 0000 0001

整形提升的例子:
//实例1
char a,b,c;
...
a = b + c;
//负数的整形提升
char c1 = -1;
变量c1的二进制位(补码)中只有8个比特位:
1111111
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为1
提升之后的结果是:
1111 1111 1111 1111 1111 1111 1111 1111
//正数的整形提升
char c2 = 1;
变量c2的二进制位(补码)中只有8个比特位:
0000 0001
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为0
提升之后的结果是:
0000 0000 0000 0000 0000 0000 0000 0001
//无符号整形提升,高位补0

//实例2
#include<stdio.h>
int main()
{
    
    
    char a = 0xb6;
    short b = 0xb600;
    int c = 0xb6000000;
    if (a == 0xb6)
    {
    
    
        printf("a");
    }
    if (b == 0xb600)
    {
    
    
        printf("b");
    }
    if (c == 0xb6000000)
    {
    
    
        printf("c");
    }
    return 0;
}
`

En el ejemplo 2, ayb deben promoverse plásticamente, pero c no necesita promoverse plásticamente. Después de que a, b se promueven plásticamente, se convierte en un número negativo, por lo que la expresión
a0xb6, bEl resultado de 0xb600 es falso, pero c no se somete a promoción plástica, el resultado de la expresión c == 0xb6000000 es verdadero. El resultado de
la salida del programa es: c

Ejemplo 2:

#include <stdio.h>
int main()
{
    
    
    char a = -1;
    //1000 0000 0000 0000 0000 0000 0000 0001 -----原码
    //1111 1111 1111 1111 1111 1111 1111 1110 -----反码
    //1111 1111 1111 1111 1111 1111 1111 1111 -----补码
    //发生截断
    //1111 1111  ----a
    //由于要打印整形(%d)格式,所以发生整形提升,前面补充符号位
    //1111 1111 1111 1111 1111 1111 1111 1111 -----补码
    //1111 1111 1111 1111 1111 1111 1111 1110 -----反码
    //1000 0000 0000 0000 0000 0000 0000 0001 -----原码
    //a那打印就是-1

    signed char b = -1;
    unsigned char c = -1;
    //1000 0000 0000 0000 0000 0000 0000 0001 -----原码
    //1111 1111 1111 1111 1111 1111 1111 1110 -----反码
    //1111 1111 1111 1111 1111 1111 1111 1111 -----补码
    //发生截断
    //1111 1111  ----c
    //由于要打印整形(%d)格式,所以发生了整形提升,前面补充符号位,但c是无符号数,所以前面补0
    //由于是正数-----补码==反码==原码
    //0000 0000 0000 0000 0000 0000 1111 1111 
    printf("a=%d,b=%d,c=%d", a, b, c); //a= -1  b= -1 c= 255
    return 0;

}

Ejemplo 3:

#include <stdio.h>
int main()
{
    
    
    char a = -128;
    //1000 0000 0000 0000 0000 0000 1000 0000 -----原码
    //1111 1111 1111 1111 1111 1111 0111 1111 -----反码
    //1111 1111 1111 1111 1111 1111 1000 0000 -----补码
    //截断
    //1000 0000 ----a
    //由于要打印无符号整形(%u)格式,所以发生整形提升,前面补充符号位
    //1111 1111 1111 1111 1111 1111 1000 0000 -----补码==反码==原码  
    printf("%u\n", a);   //打印的值-----4294967168‬
    return 0;
}

Ahora que hemos aprendido el levantamiento y el truncamiento de plástico, escribamos las siguientes preguntas:
Tema 1: ¿Qué pasará con el siguiente código?

#include<stdio.h>
int main()
{
    
    
	unsigned int i;
	for (i = 9; i >= 0; i--)        //无符号整形恒大于0,所以会死循环
	{
    
                                   //当i变成-1时,把有符号数转变位无符号数为32个1然后一直死循环下棋
                                  //1000 0000 0000 0000 0000 0000 0000 0001 -----原码
                                  //1111 1111 1111 1111 1111 1111 1111 1110 -----反码
                                  //1111 1111 1111 1111 1111 1111 1111 1111 -----补码 -1对应的无符号数
		printf("%d\n", i);
	}
	return 0;
}

El entero sin signo es siempre mayor que 0, por lo que se repetirá sin fin.

Pregunta 2: ¿Cuál es el valor impreso por el siguiente código?

#include<stdio.h>
#include<string.h>
int main()
{
    
    
    char a[1000];
    int i;
/*a是字符型数组,strlen找的是第一次出现尾零(即值为0)的位置。考虑到a[i]其实是字符型,
如果要为0,则需要 - 1 - i的低八位要是全0,也就是问题简化成了“寻找当 - 1 - i的结果第一次出现低八位全部为0的情况时,
i的值”(因为字符数组下标为i时第一次出现了尾零,则字符串长度就是i)。只看低八位的话,此时 - 1相当于255,所以i == 255的时候,
- 1 - i(255 - 255)的低八位全部都是0,也就是当i为255的时候,a[i]第一次为0,所以a[i]的长度就是255了。*/
    for (i = 0; i < 1000; i++)
    {
    
    
        a[i] = -1 - i;      //-128~127
    }
    printf("%d", strlen(a));   //strlen(a)----255
    return 0;
}

parte 3. Los extremos grande y pequeño de la calculadora

¿Qué es grande y pequeño?

Inserte la descripción de la imagen aquí
Usemos un código para ver si la plataforma que estamos usando actualmente usa almacenamiento big-endian o almacenamiento little-endian.

#include<stdio.h>
int check_sys()
{
    
    
	int i =0x00000001;     
	char* p = (char *)&i;   //让它只能访问一个字节的内容
	return *p;
}
int main()
{
    
    
	if (check_sys() == 1)
	{
    
    
		//把一个数据的低位字节序的内容,存放在低地址处
		//            高位字节的内容,存放在高位地址处
		printf("小端\n");   //1在小端内存存储的十六进制----------01 00 00 00
	}
	else
	{
    
    
		//把一个数据的低位字节序的内容,存放在高位地址处
                  //高位字节序的内容,存放在低位地址处
		printf("大端\n");   //1在大端内存存储的十六进制----------00 00 00 01
	}
	return 0;
}

Inserte la descripción de la imagen aquí
De la figura anterior, encontramos que el almacenamiento vs2019 es almacenamiento little-endian

parte 4. Almacenamiento de datos: punto flotante

De acuerdo con el estándar internacional IEEE (Instituto de Ingeniería Eléctrica y Electrónica) 754, cualquier número de coma flotante binario V puede expresarse 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 significativo, que es mayor o igual a 1 y menor que 2.
2 ^ E representa el bit de exponente.
Por ejemplo: 5.0 en decimal, 101.0 en binario, equivalente a 1.01 × 2 ^ 2. Entonces, de acuerdo con el formato de V anterior, se pueden obtener s = 0,
M = 1.01 y E = 2.
Decimal -5.0, escrito en binario es -101.0, que es equivalente a -1.01 × 2 ^ 2. Entonces, s = 1, M = 1.01 y E = 2.
IEEE 754 estipula: Para números de coma 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 los dígitos significativos M.
Inserte la descripción de la imagen aquí
Para un número de coma flotante de 64 bits, el bit más alto es el bit de signo S, los siguientes 11 bits son el exponente E y los 52 bits restantes son el dígito significativo M.
Inserte la descripción de la imagen aquí
IEEE 754 el número M y el exponente efectivo E, algunas disposiciones especiales . Como se mencionó anteriormente, 1≤M <2, es decir, M se puede escribir en la forma de 1.xxxxxx
, donde xxxxxx representa la parte decimal.
IEEE 754 estipula que al guardar M en 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 siguiente parte xxxxxx.
Por ejemplo, al guardar 1.01, solo se guarda 01, y cuando se lee, se agrega el primer 1. El propósito de esto es ahorrar 1 cifra significativa.
Tomemos como ejemplo un número de coma flotante de 32 bits. Sólo quedan 23 bits para M. Después de redondear hacia abajo el 1 en el primer dígito, es igual a 24 dígitos significativos.

En cuanto al índice E, la situación es más complicada.
Primero, E es un entero sin signo (unsigned int). Esto significa que si E tiene 8 bits, su rango de valores es 0 ~ 255; si E es 11 bits, su
rango de valores es 0 ~ 2047. Sin embargo, sabemos que, en la notación científica E es un número negativo, el IEEE 754 proporciona tiempo real en la memoria E
intermedio de valor real debe combinarse con un número, para una E de 8 bits, el número del medio es 127; Para una E de 11 dígitos, el número del medio es 1023. Por ejemplo, la E
de2 ^ 10es 10, por lo que al guardar como un número de coma flotante de 32 bits, debe guardarse como 10 + 127 = 137, que es 10001001.

Luego, el exponente E se saca de la memoria y se puede dividir en tres casos:
E no es todo 0 o no todo 1,
entonces el número de punto flotante se expresa mediante la siguiente regla, es decir, el valor calculado de el exponente E menos 127 (o 1023), obtenga el valor verdadero y agregue
1 en el primer dígito antes del número efectivo M. Por ejemplo: la forma binaria de 0.5 (1/2) es 0.1, porque la parte positiva debe ser 1, es decir, el punto decimal se desplaza 1 lugar hacia la derecha,
luego es 1.0 * 2 ^ (- 1) , y su código de orden es -1 + 127 = 126 se representa como 01111110, y la mantisa 1.0 quita la parte entera a 0, y llena de 0 a 23 bits
00000000000000000000000, entonces su representación binaria es:
E es todo 0
En este momento , el exponente E del número de coma flotante es igual a 1-127 (o 1-1023) es el valor verdadero, el dígito efectivo M ya no se suma al primer 1 sino que se restaura a
un decimal de 0.xxxxxx. Esto se hace para representar ± 0 y números muy pequeños cercanos a cero.
E es todo 1 en
este momento, si los dígitos significativos M son todos 0, significa ± infinito (positivo o negativo depende del bit de signo s);

int main()
{
    
    
	int n = 9;
	//0 00000000 00000000000000000001001 ----整数存储形式 
	//(-1)^0 * 0.00000000000000000001001 * 2^-126   ----单精度浮点数存储形式
	float *pFloat = (float *)&n;
	printf("n的值为:%d\n", n);//9
	printf("*pFloat的值为:%f\n", *pFloat);//0.000000

	*pFloat = 9.0;
	//1001.0
	//(-1)^0 * 1.001*2^3
	//S=0  ----表示的是符号位 0为正 ,负数为1
	//M=1.001
	//E=3     +127
	//9.0 -> 1001.0 ->(-1)^01.0012^3 -> s=0, M=1.001,E=3+127=130
	//01000001000100000000000000000000
	printf("num的值为:%d\n", n);//直接打印整形时,就是2进制到十进制转换
	printf("*pFloat的值为:%f\n", *pFloat);//9.0
	return 0;
}

De acuerdo, eso es todo.

Supongo que te gusta

Origin blog.csdn.net/weixin_47812603/article/details/113530893
Recomendado
Clasificación