Estructura del lenguaje C (simplificado)

La estructura es un tipo creado por nosotros mismos, lo que hace que el lenguaje C sea capaz de describir tipos complejos. Por ejemplo, los estudiantes incluyen: nombre, edad, género, número de estudiante...

conocimiento de la estructura

Una estructura es una colección de valores llamados variables miembro. Cada miembro puede ser una variable de un tipo diferente.
—————————

La diferencia entre estructura y matriz:
Matriz: es una colección de elementos del mismo tipo.
Estructura: Es una colección de valores, pero estos valores pueden ser de diferentes tipos: pueden ser escalares, arreglos, punteros o incluso otras estructuras.

declaración de la estructura

declaración general

Supongamos que un estudiante se va a describir aquí:

//描述一个学生
struct Stu   //Stu是结构体变量名,可以自定义(根据实际需求)
{
    
    
	//里面是成员列表
	char name[20];//学生名字
	int age;      //学生年龄
	char id[10];  //学生学号
	//....

}s1,s2,s3;  //这里是结构体变量,是全局变量,
           //(创建结构体类型时顺带创建3个结构体全局变量)
          //这后面的分号不能丢
int main()
{
    
    
	struct Stu s4, s5; //创建结构体变量,这些是局部变量

	return 0;
}

declaración especial

Es decir, cuando se declara la estructura, se puede declarar de forma incompleta.

tipo de estructura anónima

struct       //没有结构体变量名
{
    
    
	int a;
	char b;
	double c;
}s1;      //只能在这里创建结构体变量名,
         //且只能使用一次

referencia propia de la estructura

Definición: Una estructura debe poder encontrar la siguiente estructura del mismo tipo que ella;

  • Una estructura puede contener otra variable de estructura
struct book1
{
    
    
	char name[20];
	int age;
	int mony;
};

struct book
{
    
    
	char name[20];
	int mony;
	struct book1 s1;
};

Sin embargo, la estructura no puede tener sus propias variables de estructura, pero puede usar un puntero para apuntar a una estructura de este tipo para realizar la autorreferencia de la estructura.

struct Note
{
    
    
	int date;        //数据域
	struct Note* next;//指针域
};

Con respecto a la definición de typedef (tipo de definición) define un tipo de estructura anónima:

typedef struct
{
    
    
	int data;//数据域
	struct Node* next;//指针域
} Node;
void main() {
    
    
	Node n;
 }

Definición e inicialización de variables de estructura

Definición de variables de estructura

// struct book 是定义的数据类型的名字,它向编译系统声明这是一个“结构体类型”
struct book  
{
    
    
	int mony;
	char name[20];
}s1,s2;//全局变量(创建结构体类型时顺带创建2个结构体全局变量)
       //最后的分号千万不能省略
int main()
{
    
    
	struct book s3, s4;//局部变量
	return 0;
}

Inicialización de variables de estructura

struct book
{
int mony;
char name[20];
}s1={30,"xiyouji"}, s2 = {20,"hongloumeng"};//s1,s2也是结构体变量,其是全局变量,
//并对其全部初始化,其实也可不初始化


int main()
{
struct book s3 = { 15,"三国演义" }, s4 = {25,"水浒传"};
//创建结构体对象并完成初始化
//其中初始化一个汉字占两个字节
return 0;
}

Estructura de inicialización anidada:


struct history
{
int age;
int id;
};


struct book
{
char name[20];
int mony;
struct history s1;
};


int main()
{
struct book s1 = { "abcdef",20,{1000,2023}};//初始化完成
return 0;
}

Inicialización de tipo de estructura anónima


struct {
char name[20];
int price;
char id[12];
}s = { "git",7,"123" };

Aviso:

  • La declaración e inicialización de la estructura también se puede realizar en la función
  • Una vez definida la estructura, debe inicializarse.
  • La estructura también puede usar la forma del operador "." para operar en el valor dentro

Paso de parámetros de estructura

struct BOOK
{
    
    
	char name[20];
	int money;
};

//传值调用
void test1(struct BOOK s)
{
    
    
	printf("%s %d", s.name, s.money);
}

//传址调用
void test2(struct BOOK* ps)
{
    
    
	printf("%s %d", ps->name, ps->money);
}

int main()
{
    
    
	struct BOOK s1 = {
    
     "shuihuzhuan",20 };

	test1(s1);//传结构体,不会改变结构体变量
	test2(&s1);//传结构体地址,可以改变结构体变量

	return 0;
}

Nota:
pase la dirección del parámetro de estructura tanto como sea posible, ya que el parámetro debe insertarse en la pila. Si se pasa el objeto de estructura, la estructura es demasiado grande y el sistema para insertar el parámetro en la pila también lo es. grande, lo que conducirá a la degradación del rendimiento; llamada por
dirección Cuando se usa const, se puede usar const; la función de const en la estructura que pasa parámetros: la estructura original solo se puede leer y no cambiar, para evitar un mal funcionamiento.

Alineación de memoria de estructura

Ahora que hemos entendido el uso básico de las estructuras, exploremos una pregunta en profundidad:
¿Cómo calcular el tamaño de la estructura?
aquí está involucradoAlineación de memoria de estructura.
Para entender esto, primero introduzca unmacro (desplazamiento de()), que calcula el desplazamiento de un miembro de estructura en relación con la posición inicial de la estructura .

size_t offsetof( structName, memberName );

1. El primer parámetro es el nombre de la estructura.
2. El segundo parámetro es el miembro de la estructura.
Introduzca dos parámetros y se devolverá el desplazamiento del miembro de la estructura en relación con la posición inicial de la estructura.

Tome este código para explorar:

struct s1
{
    
    
	char c1;
	int i;
	char c2;
};

struct s2
{
    
    
	int i;
	char c1;
	char c2;
};

int main()
{
    
    
	printf("%d\n", offsetof(s1, c1));
	printf("%d\n", offsetof(s1, i));
	printf("%d\n", offsetof(s1, c2));
	return 0;
}

inserte la descripción de la imagen aquí

Cuando se conoce el desplazamiento, podemos analizar la forma en que la estructura se almacena en la memoria;
la estructura se almacena en el área de pila

inserte la descripción de la imagen aquí

En este caso, debería ser de 9 bytes, pero el resultado es de 12 bytes, ¿por qué?

inserte la descripción de la imagen aquí

Los problemas anteriores indican que los miembros de la estructura no se almacenan continuamente en la memoria en orden, sino que tienen ciertas reglas.

Reglas para la alineación de la memoria de estructura:

1. El primer miembro de la estructura siempre se coloca en un desplazamiento de 0 en comparación con la posición inicial de la variable de estructura.

2. A partir del segundo miembro, cada miembro subsiguiente debe estar alineado con una dirección que sea un múltiplo entero de un cierto número (número de alineación).Número de alineación
: la comparación entre el número de alineación predeterminado del compilador y el valor de tamaño del pequeño valor del miembro.
El número de alineación predeterminado en el compilador VS es: 8
gcc: no hay un número de alineación predeterminado y el número de alineación es el tamaño del miembro de la estructura.

3. El tamaño total de la estructura debe ser un múltiplo entero de la alineación máxima.
Alineación máxima: el valor máximo de todas las alineaciones

4. Si una estructura está anidada, la estructura anidada se alinea con un múltiplo entero de su número máximo de alineación, y el tamaño entero de la estructura es el número entero del número máximo de alineación (incluido el número de alineación de la estructura anidada) veces.

Entonces, ¿cómo usar esta regla?
Mira las fotos y habla:
inserte la descripción de la imagen aquí

Un punto especial: si la variable miembro es una matriz.


Por ejemplo: int arr [3]; simplemente trátelo como tres variables enteras y almacénelas secuencialmente.

¿Por qué alineación de memoria?

1. Razones de la plataforma:

  • No todas las plataformas de hardware pueden acceder a datos arbitrarios en cualquier dirección; algunas plataformas de hardware solo pueden obtener ciertos tipos de datos en ciertas direcciones; de lo contrario, se genera una excepción de hardware.

2. Razones de rendimiento

  • Las estructuras de datos deben alinearse en los límites naturales tanto como sea posible. La razón es la siguiente: para acceder a la memoria no alineada, el procesador necesita dos accesos a la memoria, mientras que el acceso a la memoria alineada requiere solo un acceso.

3. Explique como se muestra en la figura:
inserte la descripción de la imagen aquí
Resumen: La alineación de la memoria estructural es la práctica de intercambiar espacio por tiempo.

Por lo tanto, al diseñar la estructura, no solo debemos satisfacer la alineación, sino también ahorrar espacio:

1. Organice razonablemente el espacio de los miembros de la estructura


2. También puedes modificar la alineación por defecto

Modifique la alineación predeterminada:

#include <stdio.h>
//修改默认对齐数为1
#pragma pack(1)
struct Hand
{
    
    
	char c;
	int size;
	char q;
};
#pragma pack()//取消设置的默认对齐,还原默认
int main() {
    
    
	printf("%d\n", sizeof(struct Hand));//默认对齐数8时——12,默认对齐数1时——6
	return 0;
}

segmento de bits

Comparado con la estructura, puede ahorrar espacio, pero tiene problemas multiplataforma;

Por qué hay un segmento de bits: porque si hay 32 bits en un byte, cuando solo usa 2 bits, el otro espacio se desperdiciará, y el segmento de bits puede elegir cuánto espacio ocupa cada uno de sus miembros, por lo que puede cambiarlo Buen ahorro de espacio.

declaración de campo de bits

Su declaración es similar a la declaración de estructura, con dos diferencias:

1. Los miembros del campo de bits pueden ser de tipo int, int sin signo, int con signo o char (familia de enteros).
__
2. Hay dos puntos y un número después del nombre del miembro del segmento de bits.
__

Ejemplo:

** S es un tipo de campo de bits **

struct S
{
    
    
	char a : 3;
	char b : 4;
	char c : 5;
	char d : 4;
};

asignación de memoria de segmentos de bits

Tome el tipo de segmento de bit anterior para explorar;

1. Los miembros del segmento de bits pueden ser de tipo int, int sin signo, int con signo o char (familia de enteros)
2. El espacio del segmento de bits es de 4 bytes (int) o 1 byte (char) según se requiera 3.
Segmentos de bits implican muchos factores inciertos. Los segmentos de bits no son multiplataforma. Los programas que se centran en la portabilidad deben evitar el uso de segmentos de bits. 4. En primer lugar, los números
detrás de cada miembro son bits, que son bits binarios.

struct S
{
    
    
	//因为先是char类型,先开辟一个字节--8个bit位
	char a : 3;//a成员占3个bit
	char b : 4;//b成员占4个bit
	char c : 5;//这时用了7个bit,还剩1个,因为下面还是char类型,不够就再开辟一个字节
	//c成员在新开辟的字节占5个bit
	char d : 4;//这时还剩3个bit,char类型,开辟一个字节,d成员占4个bit
	//因此S位段类型所占3个字节
};

int main()
{
    
    
	struct S s = {
    
     0 };
	s.a = 10;
	s.b = 20;
	s.c = 3;
	s.d = 4;

	printf("%d ", sizeof S);//3
	return 0;
}

Para los datos dentro del siguiente byte del compilador VS, primero se usa la dirección del bit bajo y luego se usa la dirección del bit alto (la asignación en la memoria se usa de derecha a izquierda)
inserte la descripción de la imagen aquí

Problemas multiplataforma del segmento de bits:

1. El tipo de campo de bits int, ya sea que se considere un bit con signo o un bit sin signo, es incierto
2. No se puede determinar el número máximo de bits en un campo de bits. (Las máquinas de 16 bits tienen un máximo de 16, las máquinas de 32 bits tienen un máximo de 32, escrito como 27, habrá problemas en las máquinas de 16 bits. 3. Los miembros
en el segmento de bits se asignan de izquierda a derecha en memoria, o de derecha a izquierda. El estándar aún no ha sido definido.
4. Cuando una estructura contiene dos segmentos de bits, y el segundo segmento de bits es demasiado grande para acomodar los bits restantes del primer segmento de bits, no se sabe si descartar los bits restantes o usarlos

Resumen: en comparación con la estructura, el segmento de bits puede lograr el mismo efecto, lo que puede ahorrar espacio muy bien, pero hay un problema multiplataforma.

6 horas de hígado continuo realmente no están cubiertas ^ _ ^ Finalmente, espero que los hermanos y hermanas apoyen un poco, la próxima vez nuestro hígado explotará.

Supongo que te gusta

Origin blog.csdn.net/m0_66780695/article/details/132054437
Recomendado
Clasificación