Armazenamento de dados da linguagem C (inteiro e ponto flutuante) na memória

Índice

1. Classificação básica de tipos

1.1 Inteiro

1.2 Ponto flutuante

1.3 Tipo de construção

1.4 Tipos de ponteiro

1.5 Tipos vazios

2. Armazenamento de inteiros na memória

2.1 Números de máquinas e valores verdade

2.1.1 Número de máquinas

2.1.2 Valor de verdade

2.2 Complemento e inverso do código original

2.2.1 Código original

2.2.2 Código Inverso

2.2.3 Código complementar

2.2.4 Forma de armazenamento de dados inteiros

2.3 Introdução ao endian grande e pequeno

2.3.1 O que é big endian e little endian

2.3.2 Por que existe um modo endian grande e pequeno

2.3.3 As respectivas vantagens do armazenamento big e small endian

3. Armazenamento de números de ponto flutuante na memória

3.1 Exemplos de armazenamento de ponto flutuante

3.2 Regras para armazenamento de números de ponto flutuante

3.2.1 Representação binária e conversão decimal de números de ponto flutuante

3.2.2 Regulamentos IEEE 754

3.2.3 Regulamentos especiais da IEEE 754 sobre dígitos significativos M e expoente E:


1. Classificação básica de tipos

1.1 Inteiro

char
        não assinado char
        assinado char
curto
        não assinado curto [int]
        assinado curto [int]
int
        não assinado int
        assinado int
longo
        não assinado longo [int]
        assinado longo [int]

1.2 Ponto flutuante

flutuar
duplo

1.3 Tipo de construção

> Tipo de matriz
> Tipo de estrutura struct
> Tipo de enumeração enum
> União de tipo de junta

1.4 Tipos de ponteiro

int* pi;
char* pc;
flutuar* pf;
vazio* pv;

1.5 Tipos vazios

void significa tipo vazio (sem tipo)
geralmente aplicado ao tipo de retorno de função, parâmetro de função, tipo de ponteiro.

2. Armazenamento de inteiros na memória

Sabemos que criar uma variável é abrir espaço na memória, e o tamanho do espaço aberto varia de acordo com os diferentes tipos.Se você quiser saber como armazená-la, primeiro deve conhecer os seguintes conceitos.

2.1 Números de máquinas e valores verdade

2.1.1 Número de máquinas

A representação binária de um número em um computador é chamada de número de máquina do número. O número da máquina é assinado e o bit mais alto de um número é usado para armazenar o sinal no computador, o número positivo é 0 e o número negativo é 1.

Por exemplo, o número em decimal + 2, o comprimento da palavra do computador é de 8 bits, convertido em binário é 00000010. Se for -2, é 10000010.

Então, 00000011 e 10000011 aqui são os números das máquinas.

2.1.2 Valor de verdade

Como o primeiro bit do número da máquina é o bit de sinal, o número da máquina não é igual ao valor real. Por exemplo, no número assinado acima 10000010, o bit 1 mais alto representa negativo e seu valor real é -2 em vez do valor formal 130 (10000011 convertido em decimal é igual a 130). Portanto, para fins de distinção, o valor real correspondente ao número da máquina com o bit assinado é denominado valor real do número da máquina.

2.2 Complemento e inverso do código original

Existem três métodos de representação binária para inteiros em computadores, nomeadamente código original, código complementar e código complemento (três formas de números de máquina).
Todos os três métodos de representação têm duas partes, o bit de sinal e o bit de valor. O bit de sinal usa 0 para representar "positivo" e 1 para representar "negativo"
. Existem três maneiras diferentes de representar números inteiros negativos.

2.2.1 Código original

O código original é o valor absoluto do bit de sinal mais o valor verdadeiro , ou seja, o primeiro bit é usado para representar o sinal e os bits restantes representam o valor. Por exemplo, se for binário de 8 bits:

  • O código original de +1: [0 (bit de sinal)]+[000 0001 (bit de valor)]=0000 0001;
  • O código fonte de -1: [1 (bit de sinal)]+[000 0001 (bit de valor)]=1000 0001;

2.2.2 Código Inverso

O complemento de um de um número positivo é ele mesmo; o complemento de um de um número negativo é obtido invertendo os outros bits com base em seu código original, sem alterar o bit de sinal.

  • [+1] = [0000 0001] original = [0000 0001] anti
  • [-1] = [1000 0001] original = [1111 1110] anti

2.2.3 Código complementar

O complemento de um número positivo é ele mesmo; o complemento de um número negativo é baseado no código original, o bit de sinal permanece inalterado, o resto dos bits são invertidos e, finalmente, +1. (Ou seja, +1 com base do código inverso)

  • [+1] = [0000 0001] original = [0000 0001] inverso = [0000 0001] complemento
  • [-1] = [1000 0001] original = [1111 1110] inverso = [1111 1111] complemento

2.2.4 Forma de armazenamento de dados inteiros

Os dados inteiros são armazenados na memória na forma de código complementar. A razão é: usando o código complementar, o bit de sinal e o campo de valor podem ser processados ​​uniformemente; ao mesmo tempo, adição e subtração também podem ser processadas uniformemente (a CPU possui apenas um somador). Além disso, o processo de operação de o código complementar e o código original são os mesmos. Circuitos de hardware adicionais são necessários.

 Pela figura acima, sabemos que todos os complementos estão armazenados na memória, mas por que está na ordem de trás para frente?É porque existe uma forma de armazenamento endian grande e pequeno. A próxima etapa é introduzir o armazenamento endian grande e pequeno.

2.3 Introdução ao endian grande e pequeno

2.3.1 O que é big endian e little endian

O modo big-endian (armazenamento) significa que os bits baixos de dados são armazenados nos endereços altos da memória, enquanto os bits altos de dados são armazenados nos endereços baixos da memória
;
o
modo little-endian (armazenamento) significa que os bits de dados mais baixos são armazenados no endereço inferior, enquanto os bits de dados de ordem mais alta são armazenados no
endereço mais alto da memória.

Nesta imagem, os bits baixos típicos são armazenados no endereço baixo da memória, e os bits altos dos dados são armazenados no endereço alto da memória (modo de armazenamento little endian).

2.3.2 Por que existe um modo endian grande e pequeno

Por que existe uma diferença entre os modos big e small endian? Isso ocorre porque no sistema de computador usamos bytes como unidade, e cada unidade de endereço
corresponde a um byte, e um byte tem 8 bits. Mas na linguagem C, além do char de 8 bits, também existem
tipos curtos de 16 bits e tipos longos de 32 bits (dependendo do compilador específico).Além disso, para processadores com mais de 8 bits, como Processador de 16 bits ou 32
bits, como a largura do registro é maior que um byte, deve haver um problema de como organizar vários bytes. Portanto
, isso leva ao modo de armazenamento big-endian e ao modo de armazenamento little-endian.
Por exemplo: um tipo curto de 16 bits x, o endereço na memória é 0x0010, o valor de x é 0x1122, então 0x11 é o
byte alto e 0x22 é o byte baixo. Para o modo big-endian, coloque 0x11 no endereço inferior, ou seja, 0x0010, e coloque 0x22 no
endereço superior, ou seja, 0x0011. Modo Little Endian, exatamente o oposto. Nossa estrutura X86 comumente usada é o modo little-endian, enquanto KEIL C51
é o modo big-endian. Muitos ARMs e DSPs estão no modo little-endian.
Alguns processadores ARM também podem escolher o modo big-endian ou o modo little-endian por hardware .

2.3.3 As respectivas vantagens do armazenamento big e small endian

Vantagens do modo little endian :

  • O endereço baixo da memória armazena o byte baixo, portanto não há necessidade de ajustar o conteúdo do byte ao converter os dados (Nota: Por exemplo, ao converter 4 bytes de int em 2 bytes de short, os dados int são armazenados diretamente Basta fornecer os dois primeiros bytes para short, porque os dois primeiros bytes são apenas os dois bytes mais baixos, o que está em conformidade com a lógica de conversão);
  • Quando a CPU faz cálculos numéricos, ela busca os dados da memória em ordem de menor para maior para cálculo até que o bit de sinal mais alto seja atualizado no final. Este método de operação será mais eficiente.

Vantagens do modo big endian :

  • O bit de sinal está no primeiro byte da memória dos dados representados, o que é conveniente para julgar rapidamente o positivo e o negativo e o tamanho dos dados
  • Suas respectivas vantagens são as desvantagens uma da outra. Como os dois são iguais, juntamente com a insistência de alguns fabricantes de hardware, nunca existe um padrão unificado para ordem de armazenamento multibyte.

3. Armazenamento de números de ponto flutuante na memória

3.1 Exemplos de armazenamento de ponto flutuante

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

E o resultado da execução deste código é:

 

 Mas por que existe uma lacuna tão grande entre os resultados da interpretação de números inteiros e de ponto flutuante do mesmo número, então precisamos entender as regras de armazenamento de números de ponto flutuante.

3.2 Regras para armazenamento de números de ponto flutuante

3.2.1 Representação binária e conversão decimal de números de ponto flutuante

 3.2.2 Regulamentos IEEE 754

De acordo com o padrão internacional IEEE (Instituto de Engenharia Elétrica e Eletrônica) 754, qualquer número binário de ponto flutuante V pode ser expresso da seguinte forma:

  • (-1)^S * M * 2^E
  • (-1)^S representa o bit de sinal, quando S=0, V é um número positivo; quando S=1, V é um número negativo.
  • M representa um número válido, maior ou igual a 1 e menor que 2.
  • 2^E significa bits expoentes.
     

 por exemplo:

  • 5,0 em decimal é 101,0 em binário, o que equivale a 1,01×2^2.
  • Então, de acordo com o formato de V acima, pode-se concluir que S=0, M=1,01 e E=2.
  • Decimal -5,0, escrito em binário é -101,0, o que equivale a -1,01×2^2. Então, S=1, M=1,01, E=2.

Modelo de armazenamento de número de ponto flutuante: 

 (1) Para números de ponto flutuante de 32 bits, o 1 bit mais alto é o bit de sinal s, os próximos 8 bits são o expoente E e os 23 bits restantes são o número efetivo M.

 (2) Para números de ponto flutuante de 64 bits, o bit mais alto é o bit de sinal S, os próximos 11 bits são o expoente E e os 52 bits restantes são o número efetivo M.

3.2.3 Regulamentos especiais da IEEE 754 sobre dígitos significativos M e expoente E:

1. Regulamentos especiais para o efetivo número M:

Conforme mencionado anteriormente, 1≤M<2, ou seja, M pode ser escrito na forma 1.xxxxxx, onde xxxxxx representa a parte decimal.
A IEEE 754 estipula que quando M é salvo dentro do computador, o primeiro dígito deste número é sempre 1 por padrão, portanto pode ser descartado, e apenas a parte seguinte xxxxxx é salva. Por exemplo, ao salvar 1.01, salve apenas 01 e adicione o primeiro 1 ao ler. O objetivo de fazer isso é economizar 1 algarismo significativo. Tomando como exemplo o número de ponto flutuante de 32 bits, restam apenas 23 bits para M. Depois que o primeiro 1 é descartado, isso equivale a salvar 24 algarismos significativos.

2. Disposições especiais para o Índice E:

1.1 Regulamentos sobre números intermediários (para distinguir expoentes positivos e negativos)

Primeiro, E é um número inteiro sem sinal (unsigned int), o que significa que se E tiver 8 bits, seu intervalo de valores será de 0 a 255; se E tiver 11 bits, seu intervalo de valores será de 0 a 2047. Porém, sabemos que E em notação científica pode ter números negativos, por isso a IEEE 754 estipula que um número intermediário deve ser adicionado ao valor real de E quando armazenado na memória. Para E de 8 bits, esse número intermediário é 127 ; para 11 -bit E, esse número intermediário é 1023 . Por exemplo, o E de 2 ^ 10 é 10, portanto, ao salvá-lo como um número de ponto flutuante de 32 bits, ele deve ser salvo como 10+127=137, que é 10001001

1.2 E nem tudo é 0 ou nem tudo 1

Neste momento, o número de ponto flutuante é representado pelas seguintes regras, ou seja, o valor calculado do expoente E é subtraído por 127 (ou 1023) para obter o valor real, e então o primeiro dígito 1 é adicionado antes
do número efetivo M.
Por exemplo:
A forma binária de 0,5 (1/2) é 0,1. Como a parte positiva deve ser 1, ou seja, o ponto decimal é deslocado 1 bit para a direita, então é 1,0*2^(-1
) , e seu código de pedido é -1+127= 126, expresso como 01111110, e a mantissa 1.0 remove a parte inteira para ser 0, e preenche de 0 a 23 dígitos 00000000000000000000000, então sua representação binária é:

0 01111110 00000000000000000000000

1,3 E é tudo 0

Neste momento, o expoente E do número de ponto flutuante igual a 1-127 (ou 1-1023) é o valor real, e o número efetivo M não é mais adicionado com o primeiro dígito de 1, mas é restaurado para um decimal de 0,xxxxxx. Isso é feito para representar ±0 e números muito pequenos próximos de 0.

1,4 E é tudo 1

Neste momento, se o número significativo M for todo 0, significa ± infinito (positivo ou negativo depende do bit de sinal s);
 

Finalmente: o texto do código não é fácil, peça três links com um clique.

Acho que você gosta

Origin blog.csdn.net/qq_64293926/article/details/127351107
Recomendado
Clasificación