[C Avanzado] Tipo personalizado (2) Segmento de bits - Enumeración - Unión

contenido

1. Segmento de bits

      1.1, que es un segmento de bits

      1.2 Asignación de memoria del segmento de bits

      1.3 Problemas multiplataforma de segmento de bits

      1.4, la aplicación del segmento de bits

2. Enumeración

      2.1, la definición del tipo de enumeración

      2.2, las ventajas de la enumeración

      2.3, el uso de la enumeración

3. Unidos

      3.1 Definición de tipos de unión

      3.2, las características de la junta

      3.3 Cálculo del tamaño de la junta


1. Segmento de bits

1.1, que es un segmento de bits

  • La declaración y la estructura de los campos de bits son similares, con dos diferencias:
  1. Los miembros del campo de bits deben ser int, int sin signo o int con signo.
  2. El nombre del miembro del campo de bits va seguido de dos puntos y un número.
  • por ejemplo:
#include<stdio.h>
struct A
{
	int _a : 2;
	int _b : 5;
	int _c : 10;
	int _d : 30;
};
int main()
{
	printf("%d\n", sizeof(struct A)); //8
	return 0;
}
  • A es un tipo de segmento de bit. ¿Cuál es el tamaño de ese segmento A?
  • Analizar gramaticalmente:

En el código anterior, _a: 2 significa que _a solo necesita 2 bits, _b: 5 significa que _b solo necesita 5 bits, _c: 10 significa que _c solo necesita 10 bits, _d: 30 significa que _d solo necesita 10 bits Se requieren 30 bits. La suma de todos estos bits hace un total de 47 bits, entonces, ¿cómo es que hay 8 bytes? Es necesario comprender la siguiente asignación de memoria del segmento de bits:

1.2 Asignación de memoria del segmento de bits

  1. Los miembros del campo bit pueden ser de tipo int unsigned int signed int o char (perteneciente a la familia de los enteros)
  2. El espacio del campo de bits se abre en 4 bytes (int) o 1 byte (char), según sea necesario.
  3. Los campos de bits implican muchos factores inciertos. Los campos de bits no son multiplataforma. Los programas que se centran en la portabilidad deben evitar el uso de campos de bits.
  • En resumen:

_a es de tipo int Primero abre 4 bytes, _a ocupa 2 bits, y quedan 30 bits, _b ocupa 5 bits, y quedan 25 bits, _c ocupa 10 bits, y quedan 15 bits, y el tamaño de 15 bits no es suficiente _d El tamaño de _d es de 30 bits, y _d sigue siendo de tipo int, por lo que se abren 4 bytes nuevamente y se carga el tamaño de _d, por lo que el tamaño del segmento de bits A es de 8 bytes.

  • Otro ejemplo:
#include<stdio.h>
struct S
{
	char a : 3;
	char b : 4;
	char c : 5;
	char d : 4;
};
int main()
{
	printf("%d\n", sizeof(struct S));//3
	struct S s = { 0 };
	s.a = 10;
	s.b = 12;
	s.c = 3;
	s.d = 4;
	return 0;
}

En este momento a es de tipo char, primero abre 1 byte, a ocupa 3 bits, y quedan 5, b ocupa 4 bits, y queda 1 bit, y se abren los 5 bits que no le alcanzan a c, y luego se abre 1. A c se le asigna un byte con 5 bits, y quedan 3, que no alcanza para d, y alcanza para abrir 1 byte más. En resumen, el tamaño de 3 bytes se abre en este momento. Esta situación es una pérdida de espacio. Ese 1 bit se desperdicia, pero no hay manera.

  • Los segmentos de bits pueden ahorrar espacio hasta cierto punto, pero también un desperdicio moderado de espacio (pequeño).
  • Haz un dibujo para explicar la situación específica del desarrollo del espacio:

Para probar la conclusión en la figura, active el monitoreo en el compilador VS y observe la memoria:

1.3 Problemas multiplataforma de segmento de bits

  • Los campos de bits en sí mismos no son multiplataforma por las siguientes razones:
  1.  Es indeterminado si un campo de bit int se trata como firmado o sin firmar.
  2.  No se puede determinar el número máximo de bits en el campo de bits. (La máquina de 16 bits tiene un máximo de 16 bits, la máquina de 32 bits tiene un máximo de 32 bits, escrito como 27 bits, habrá problemas en una máquina de 16 bits)
  3.  No está definido si los miembros de un campo de bits se asignan en la memoria de izquierda a derecha o de derecha a izquierda.
  4.  Cuando una estructura contiene dos campos de bits, y los miembros del segundo campo de bits son demasiado grandes para caber en los bits restantes del primer campo de bits, no está claro si descartar los bits restantes o usarlos.
  • Resumir:

En comparación con la estructura, el segmento de bits puede lograr el mismo efecto, pero puede ahorrar espacio muy bien, pero hay problemas entre plataformas.

1.4, la aplicación del segmento de bits

  •  En comparación con la estructura, el segmento de bits puede lograr el mismo efecto, pero puede ahorrar espacio muy bien, incluso si hay problemas entre plataformas.

2. Enumeración

  • La enumeración, como su nombre indica, es una enumeración. Haz una lista de los posibles valores.

  • Por ejemplo en nuestra vida real:
  1. El lunes a domingo de la semana está limitado a 7 días, que se pueden enumerar uno por uno.
  2. El género es: masculino, femenino, confidencial, también puede enumerarlos uno por uno.
  3. Hay 12 meses en el mes, también puede enumerarlos uno por uno
  • Aquí es donde se pueden usar las enumeraciones.
  • Nota: el tamaño del tipo de enumeración siempre es de 4 bytes.

2.1, la definición del tipo de enumeración

#include<stdio.h>
enum Day//星期
{
	Mon,
	Tues,
	Wed,
	Thur,
	Fri,
	Sat,
	Sun
};
int main()
{
	printf("%d %d %d %d %d %d %d\n", Mon, Tues, Wed, Thur, Fri, Sat, Sun);
	return 0;
}

El enum Day definido anteriormente es un tipo de enumeración. El contenido en { } son los valores posibles del tipo de enumeración, también llamada constante de enumeración. A partir de los resultados de ejecución, no es difícil encontrar que la enumeración tiene un valor inicial. De forma predeterminada, la primera constante de enumeración es 0 y el orden descendente es +1. Por supuesto, el valor inicial también se puede asignar al definir.

  • P.ej:
#include<stdio.h>
enum Day//星期
{
	Mon = 1,
	Tues,
	Wed,
	Thur = 3,
	Fri = 8,
	Sat,
	Sun = 0
};
int main()
{
	printf("%d %d %d %d %d %d %d\n", Mon, Tues, Wed, Thur, Fri, Sat, Sun);
	return 0;
}

2.2, las ventajas de la enumeración

#define MALE 4
#define FEMALE 5
#define SECRET 6

typedef enum Sex
{
	MALE=4,
	FEMALE,
	SECRET
}Sex;
  • Podemos usar #define para definir constantes, ¿por qué usar enumeraciones?
  • Ventajas de la enumeración:
  1.  Aumente la legibilidad y el mantenimiento del código
  2.  Las enumeraciones tienen verificación de tipo y son más rigurosas en comparación con los identificadores definidos por #define.
  3.  Previene la contaminación de nombres (encapsulación)
  4.  fácil de depurar
  5.  Fácil de usar, puede definir múltiples constantes a la vez

2.3, el uso de la enumeración

enum Color//颜色
{
	RED = 1,
	GREEN = 2,
	BLUE = 4
};
enum Color clr = GREEN;//只能拿枚举常量给枚举变量赋值,才不会出现类型的差异。
clr = 5; //ok??  err错误,左右类型不一致

3. Unidos

3.1 Definición de tipos de unión

  • Las uniones también son un tipo personalizado especial.

Las variables definidas por este tipo también contienen una serie de miembros, caracterizados por el hecho de que estos miembros comparten el mismo espacio (por lo que la unión también se llama unión).

#include<stdio.h>
//联合类型的声明
union Un
{
	char c; //1
	int i;  //4
};
int main()
{
	//联合变量的定义
	union Un u;
	//计算联合变量的大小
	printf("%d\n", sizeof(u)); //4
	return 0;
}
  • El acceso a la unión es similar al de la estructura, y se puede utilizar el operador . o el operador puntero ->.
union un x;
x.a = 10;
union un* p = &x;
p->a;

3.2, las características de la junta

Los miembros de la unión comparten el mismo espacio de memoria, por lo que el tamaño de dicha variable de unión es al menos el tamaño del miembro más grande (porque la unión debe al menos poder guardar el miembro más grande)

#include<stdio.h>
union Un
{
	char c; //1
	int i;  //4
};
int main()
{
	union Un u;
	//计算联合变量的大小
	printf("%d\n", sizeof(u)); 
	printf("%p\n", &u);
	printf("%p\n", &u.c);
	printf("%p\n", &u.i);
	return 0;
}

  • Usando la distribución espacial de la unión, el tamaño final se puede juzgar hábilmente:
#include<stdio.h>
union un
{
	int a;
	char b;
};
int main()
{
	union un x;
	x.a = 1;
	if (x.b == 1)
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}
	return 0;
}
  •  Analizar gramaticalmente:

Aquí necesitamos guardar un conjunto de secuencias binarias 0x 00 00 00 01 en el espacio correspondiente a A. En este momento, cada uno de los cuatro bytes tiene una dirección, y la dirección tiene un nivel alto y bajo, y nuestros datos son de 1 bit. correspondiente al byte Al dividir, los datos tienen bits de peso alto y bajo, por lo que hay dos esquemas de almacenamiento, uno con bits de peso alto en direcciones altas y bits de peso bajo en direcciones bajas, como el método de almacenamiento izquierdo en el anterior figura, 01 se coloca en la dirección baja. El segundo esquema es el opuesto. Como se muestra en el lado derecho de la figura anterior, 01 se coloca en la dirección alta, porque b siempre está en la dirección baja de a, y b ocupa un byte, como se muestra en la figura anterior xb=1 El marcador rojo se divide, si el esquema de almacenamiento es el primero, entonces b=1, si es el segundo, entonces b=0, y el primer esquema de almacenamiento es el regla de almacenamiento de little-endian, y la segunda es la regla de almacenamiento de big-endian.

El compilador sabe que es little endian:

3.3 Cálculo del tamaño de la junta

  1. El tamaño de la unión es al menos el tamaño del miembro más grande.
  2. Cuando el tamaño máximo del miembro no es un múltiplo entero del número de alineación máximo, debe alinearse con un múltiplo entero del número de alineación máximo.
  • P.ej:
#include<stdio.h>
union Un1
{
	char c[5];
	int i;
};
union Un2
{
	short c[7];
	int i;
};
int main()
{
	printf("%d\n", sizeof(union Un1)); //8
	printf("%d\n", sizeof(union Un2)); //16
	return 0;
}
  • Analizar Un1 como tamaño 8:

Dado que el tamaño del tipo char es de 1 byte y el número de alineación predeterminado del compilador es de 8 bytes, el valor más pequeño del número de alineación es 1 byte, el tamaño del tipo int es de 4 bytes y el valor más pequeño del número de alineación es de 4 bytes. En este momento, el número de alineación máximo es de 4 bytes y el carácter c[5] representa al menos 5 bytes de tamaño y, dado que es un múltiplo entero del número de alineación máximo 4, se aumenta a 8 bytes.

  • Explique el tamaño de Un2 16 bytes:

short c[7] significa que el tamaño de la unión es de al menos 14 bytes, el tamaño del tipo short en sí es de 2 bytes, el número de alineación predeterminado del compilador es de 8 bytes, el valor más pequeño es de 2 bytes, el tipo int en sí mismo es de 4 bytes, compile El número de alineación es de 8 bytes, el valor más pequeño de esta alineación es de 4 bytes, la alineación máxima es de 4 bytes y 14 no es un múltiplo entero de 4, por lo que se incrementa a 16 bytes.

Supongo que te gusta

Origin blog.csdn.net/bit_zyx/article/details/122685180
Recomendado
Clasificación