Estrutura da linguagem C (simplificada)

A estrutura é um tipo criado por nós mesmos, o que torna a linguagem C capaz de descrever tipos complexos. Por exemplo, os alunos incluem: nome, idade, sexo, número do aluno...

cognição da estrutura

Uma estrutura é uma coleção de valores chamados variáveis ​​de membro. Cada membro pode ser uma variável de um tipo diferente.
—————————

A diferença entre estrutura e array:
Array: é uma coleção de elementos do mesmo tipo.
Estrutura: É uma coleção de valores, mas esses valores podem ser de diversos tipos: podem ser escalares, arrays, ponteiros, ou até mesmo outras estruturas.

declaração da estrutura

declaração geral

Suponha que um aluno deva ser descrito aqui:

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

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

	return 0;
}

declaração especial

Ou seja, quando a estrutura é declarada, ela pode ser declarada incompleta.

tipo de estrutura anônima

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

auto-referência de estrutura

Definição: Uma estrutura deve ser capaz de encontrar a próxima estrutura do mesmo tipo que ela;

  • Uma struct pode conter outra variável struct
struct book1
{
    
    
	char name[20];
	int age;
	int mony;
};

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

No entanto, a estrutura não pode ter suas próprias variáveis ​​de estrutura, mas pode usar um ponteiro para apontar para uma estrutura desse tipo para realizar a auto-referência da estrutura

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

Em relação ao typedef (tipo de definição), a definição define um tipo struct anônimo:

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

Definição e inicialização de variáveis ​​de estrutura

Definição de variáveis ​​de estrutura

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

Inicialização de variáveis ​​de estrutura

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;
}

Inicialização aninhada da estrutura:


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;
}

Inicialização anônima do tipo struct


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

Perceber:

  • A declaração e inicialização da estrutura também podem ser realizadas na função
  • Depois que a estrutura é definida, ela deve ser inicializada
  • A estrutura também pode usar a forma do operador "." para operar no valor dentro

Passagem de parâmetro de estrutura

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:
passe o endereço do parâmetro da estrutura o máximo possível, porque o parâmetro precisa ser colocado na pilha. Se o objeto da estrutura for passado, a estrutura é muito grande e a abertura do sistema do push do parâmetro é muito grande, portanto, levará à degradação do desempenho; chamada por
endereço Ao usar const, const pode ser usado; o papel de const na passagem de parâmetros de estrutura: a estrutura original só pode ser lida e não alterada, para evitar operações incorretas.

Alinhamento da memória da estrutura

Agora que entendemos o uso básico das estruturas, vamos explorar uma questão mais profunda:
Como calcular o tamanho da estrutura?
aqui está envolvidoAlinhamento da memória da estrutura.
Para entendê-los, primeiro introduza ummacro (offsetof()), que calcula o deslocamento de um membro struct em relação à posição inicial do struct .

size_t offsetof( structName, memberName );

1. O primeiro parâmetro é o nome da estrutura
2. O segundo parâmetro é o membro da estrutura
Insira dois parâmetros e o deslocamento do membro da estrutura em relação à posição inicial da estrutura será retornado.

Pegue 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;
}

insira a descrição da imagem aqui

Quando o deslocamento é conhecido, podemos analisar a forma como a estrutura é armazenada na memória;
a estrutura é armazenada na área da pilha

insira a descrição da imagem aqui

Nesse caso, deveria ser 9 bytes, mas o resultado é 12 bytes, por quê?

insira a descrição da imagem aqui

Os problemas acima indicam que os membros da estrutura não são armazenados continuamente na memória em ordem, mas possuem certas regras.

Regras para alinhamento da memória da estrutura:

1. O primeiro membro da estrutura é sempre colocado em um deslocamento de 0 em comparação com a posição inicial da variável da estrutura.

2. A partir do segundo membro, cada membro subseqüente deve ser alinhado a um endereço que é um número inteiro múltiplo de um determinado número (número de alinhamento). Número de alinhamento: a
comparação entre o número de alinhamento padrão do compilador e o valor de tamanho do membro de pequeno valor.
O número de alinhamento padrão no compilador VS é: 8
gcc: Não há número de alinhamento padrão e o número de alinhamento é o tamanho do membro da estrutura.

3. O tamanho total da estrutura deve ser um múltiplo inteiro do alinhamento máximo.
Alinhamento máximo: o valor máximo de todos os alinhamentos

4. Se uma estrutura é aninhada, a estrutura aninhada é alinhada a um múltiplo inteiro de seu número de alinhamento máximo e o tamanho inteiro da estrutura é o número inteiro do número de alinhamento máximo (incluindo o número de alinhamento da estrutura aninhada) vezes.

Então, como usar essa regra?
Veja as fotos e fale:
insira a descrição da imagem aqui

Um ponto especial: se a variável de membro for uma matriz.


Por exemplo: int arr [3]; apenas trate-o como três variáveis ​​inteiras e armazene-as sequencialmente.

Por que alinhamento de memória?

1. Razões da plataforma:

  • Nem todas as plataformas de hardware podem acessar dados arbitrários em qualquer endereço; algumas plataformas de hardware podem buscar apenas determinados tipos de dados em determinados endereços, caso contrário, uma exceção de hardware é lançada.

2. Motivos de desempenho

  • As estruturas de dados devem ser alinhadas em limites naturais tanto quanto possível. A razão é esta: para acessar a memória não alinhada, o processador precisa de dois acessos à memória; enquanto o acesso à memória alinhada requer apenas um acesso.

3. Explique como mostrado na figura:
insira a descrição da imagem aqui
Resumo: O alinhamento da memória da estrutura é a prática de trocar espaço por tempo

Portanto, ao projetar a estrutura, devemos não apenas atender ao alinhamento, mas também economizar espaço:

1. Organize razoavelmente o espaço do membro da estrutura


2. Você também pode modificar o alinhamento padrão

Modifique o alinhamento padrão:

#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 com a estrutura, pode economizar espaço, mas apresenta problemas de plataforma cruzada;

Por que existe um segmento de bit: porque se houver 32 bits em um byte, quando você usar apenas 2 bits, o outro espaço será desperdiçado e o segmento de bit poderá escolher quanto espaço cada um de seus membros ocupará, para que você possa alterá-lo. Boa economia de espaço.

declaração de campo de bits

Sua declaração é semelhante à declaração de estrutura, com duas diferenças:

1. Os membros do campo de bits podem ser do tipo int, unsigned int, assinado int ou char (família inteira).
__
2. Há dois pontos e um número após o nome do membro do segmento de bit.
__

Exemplo:

** S é um tipo de campo de bit **

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

alocação de memória de segmento de bit

Pegue o tipo de segmento de bit acima para explorar;

1. Os membros do segmento de bit podem ser int, unsigned int, assinado int ou char (integer family) tipo
2. O espaço do segmento de bit é de 4 bytes (int) ou 1 byte (char) conforme necessário 3.
Segmentos de bit envolvem muitos fatores incertos. Segmentos de bits não são multiplataforma. Programas que se concentram na portabilidade devem evitar o uso de segmentos de bits. 4. Em primeiro lugar, os números
atrás de cada membro são bits, que são bits binários.

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 os dados dentro do próximo byte do compilador VS, o endereço do bit baixo é usado primeiro e, em seguida, o endereço do bit alto é usado (a alocação na memória é usada da direita para a esquerda)
insira a descrição da imagem aqui

Problemas de plataforma cruzada de segmento de bits:

1. O tipo de campo de bit int, se é considerado um bit assinado ou não assinado, é incerto,
2. O número máximo de bits em um campo de bit não pode ser determinado. (máquinas de 16 bits têm no máximo 16, máquinas de 32 bits têm no máximo 32, escrito como 27, haverá problemas em máquinas de 16 bits. 3.
Os membros no segmento de bit são alocados da esquerda para a direita em memória, ou da direita para a esquerda. O padrão ainda não foi definido.
4. Quando uma estrutura contém dois segmentos de bits e o segundo segmento de bits é muito grande para acomodar os bits restantes do primeiro segmento de bits, é incerto se deve descartar os bits restantes ou usá-los

Resumo: Comparado com a estrutura, o segmento de bits pode obter o mesmo efeito, o que pode economizar muito espaço, mas há um problema de plataforma cruzada.

6 horas de fígado contínuo realmente não é coberto ^ _ ^ Finalmente, espero que irmãos e irmãs apoiem um pouco, da próxima vez nosso fígado vai explodir.

Acho que você gosta

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