Representação de Dados
Representação binária
Exemplo: 1521310 = 111011011011012
Vantagens:
• Implementação eletrônica
– Possibilidade de armazenar elementos com dois estados
– Transmissão eletrônica confiável (robustez a ruídos)
– Implementação efienciente de operações artitméticas
0
3.3V
2.8V
0.5V
0.0V
1
0
Byte = 8 bits
Faixa de valores em diferentes
representações:
– Binário: 000000002
111111112
– Decimal:
010
25510
– Hexadecimal
0016
FF16
• Representação na base 16
• Dígitos são ‘0’ - ‘9’ e ‘A’ - ‘F’
• Escreva FA1D37B16 em C como
0xFA1D37B ou 0xfa1d37b
0
1
2
3
4
5
6
7
8
9
A
B
C
D
E
F
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111
Conversão entre bases
• De base b para base 10
• De base 10 para base b
– Divisões sucessivas por b; a cada iteração i o resto
contém o numeral ai
void num2string(int num, int base, char *b, int size)
{
int div, resto;
int i = size - 2;
div = num;
while (div && i >= 0) {
resto = div % base;
if (resto < 10) b[i] = resto + '0';
else
b[i] = (resto -10) + 'A';
div /= base;
i--;
}
}
...
char buffer[11]; buffer[10]=0;
num2string(num, base, buffer,11);
A palavra (word)
Cada máquina tem seu tamanho de palavra:
=número de bits ocupados por um valor inteiro
=número de bits de endereços
• A maioria das atuais máquinas tem palavra de
32 bits (4 bytes)
• Diferentes tipos de dados (p.ex. char, double)
podem ocupar uma fração ou múltiplo do
tamanho da palavra, mas sempre um número
inteiro de bytes;
Tamanhos de Tipos em C
…em bytes
– Tipo C
•
•
•
•
•
•
•
•
Alpha(64 bit)
int
long int
char
short
float
double
long double
ponteiro (tipo *)
4
8
1
2
4
8
8
8
32-bit
4
4
1
2
4
8
8
4
Obs: sizeof(T) retona o número de bytes usado por tipo T
IA32
4
4
1
2
4
8
10/12
4
Memória orientada a palavras
• Memória é um vetor de
bytes (cada um com um
endereço), mas acesso
ocorre palavra a palavra
• Endereço corresponde ao
primeiro byte da palavra
• Endereços de palavras
subsequentes diferem de 4
em máquina de 32 bits
32-bit 64-bit
Words Words
Addr
=
0000
??
Addr
=
0000
??
Addr
=
0004
??
Addr
=
0008
??
Addr
=
0012
??
Addr
=
0008
??
Bytes Ender.
0000
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
Ordenação de bytes
Como organizar os bytes de uma palavra (4 bytes)?
• Big Endian (computadores Sun, Mac)
– byte menos significativo com maior endereço
• Little Endian (computadores Alpha, PCs)
– Byte menos significativo no menor endereço
• Exemplo
– variável y tem tem valor 0x01234567 (hexa)
– Endereço &y é 0x100
Big Endian
0x100 0x101 0x102 0x103
01
Little Endian
23
45
67
0x100 0x101 0x102 0x103
67
45
23
01
Ordenação de Bytes
• Transparente para o programador C
• Relevante quando analisamos o código de
máquina
• Exemplo (litte endian):
01 05 64 94 04 08
add $Ox8049464 %eax
• Importante também para a transmissão de
dados entre máquinas big e little endian
Verificar se a máquina é big ou
little endian
#include <stdio.h>
typedef unsigned char *byte_ptr;
void mostra (byte_ptr inicio, int tam) {
int i;
for (i=0;i<tam;i++)
printf("%.2x", inicio[i]);
printf("\n");
}
void mostra_int (int num) {
mostra((byte_ptr) &num, sizeof(int));
}
Caracteres
• Usa-se uma tabela para mapear inteiros (não negativos)
em símbolos
• Tabelas mais comuns:
– ASCII – codificação em 8 bits
‘a’
‘z’
97
122
0x61
0x7A
‘A’
65
0x41
– UNICODE – codificação em 16 bits
• Em C, tipo char define apenas 1 byte
• Pode-se manipular um char como um int
– Exemplo: if (c > ‘0’) val = c – ‘0’;
Operadores bit a bit em C
• Podem ser aplicados a qualquer tipo C
• Baseados na algebra booleana (1 = true, 0 = false)
• And
• Or
– A & B = 1 quando A=1 e B=1
• Not
& 0 1
0 0 0
1 0 1
– ~A = 1 quando A=0
~
0 1
1 0
– A | B = 1 quando A=1 ou B=1
| 0 1
0 0 1
1 1 1
• Or exclusivo (Xor)
– A ^ B = 1 quando A=1 ou B=1,
mas não ambos
^ 0 1
0 0 1
1 1 0
Exemplos
int a, b, c;
a = 0xFF00;
b = 0x00FF;
c
c
c
c
=
=
=
=
a | b;
a & b;
~a;
a ^b;
/* a = 1111 1111 0000 0000 */
/* b = 0000 0000 1111 1111 */
/* c = 0xFFFF */
/* c = 0x0000 */
/* c = 0x00FF */
• Swap sem terceira variável:
void troca (int *x, int *y)
{
*x = *x ^ *y;
*y = *x ^ *y;
*x = *x ^ *y;
}
Deslocamento de bits
Deslocamento de bits (bit shifting):
• x << n: shift p/ esquerda ( equivale a * 2n)
• x >> n: shift p/ direita ( equivale a / 2n)
– Shift lógico: bits mais significativos preenchidos com bit 0
– Shift aritmético: bits mais significativos preenchidos com
o bit mais significativo original.
• Exemplo:
short int a, b, c;
a = 0xF;
b = 0x3C;
c = a << 4;
c = b >> 2;
/*
/*
/*
/*
a
b
c
c
=
=
=
=
0000
0011
0xF0
0000
1111
*/
1100
*/
*/
1111 = 0xF */
Representação de tipos
estruturados: arrays
• Alocação contígua na memória
• Primeiro elemento (a[0]) corresponde ao menor
endereço de memória
• Tipo a[tam] ocupa sizeof(Tipo)*tam bytes
• O nome do array equivale a um ponteiro (cujo valor não
pode ser alterado)
• Exemplo: int a[tam], a é ponteiro constante tipo
int *, e seu valor é &a[0]
• Nomes de arrays passados como parâmetros são
endereços (do array)
Aritmética básica com ponteiros
Ponteiro é um endereço para um tipo específico de dado.
P.ex. int *, char *, etc.
Seja a declaração T *pa
• Expressão *pa significa objeto T apontado por pa. E pa
significa (endereço de objeto).
• Expressão (pa +i) = pa + sizeof(T)*i
• Exemplo: se int *pi, então (pi +3) é um
deslocamento de 12 bytes do endereço pi.
• O que significam?
pa++, ++pa, (*p)++
• Comparação entre ponteiros (p == q, p >q ) só se são para
o mesmo tipo
• Subtração entre dois ponteiros, (p1 – p2), indica o número
de elementos entre p1 e p2
• Existe equivalência entre arrays e ponteiros
Alocação para Arrays
• Seja T A[L];
– Array de tipo T e comprimento L
– Alocação contígua de L * sizeof(T) bytes
• Exemplos:
char string[12];
x
x + 12
int val[5];
x
x+4
x+8
x + 12
x + 16
x + 20
double a[4];
x
x+8
x + 16
char *p[3];
x
x+4
x+8
x + 24
x + 32
Arrays Aninhados
#define PCOUNT 4
typedef int vetor[5];
vetor a[PCOUNT] =
{{1, 5, 2, 0, 6},
{1, 5, 2, 1, 3 },
{1, 5, 2, 1, 7 },
{1, 5, 2, 2, 1 }};
vetor
a[4];
1 5 2 0 6 1 5 2 1 3 1 5 2 1 7 1 5 2 2 1
76
96
116
136
156
– Declaração “vetor a[4]” equivalente a “int a[4][5]”
• Variável a denota array de 4 elementos
– Alocados continuamente
• Cada elemento é um vetor de 5 int’s
– Alocados continuamente
– Ordenação é por linha da matriz (elementos do vetor mais externo)
Alocação de Arrays Aninhados
• Declaração
T A[R][C];
– Tipo T
– R linhas, C colunas
– Elemento do tipo T ocupa K
bytes
• Tamanho do Array
– R * C * K bytes
• Ordenação principal por linha
A[0][0]
•
•
•
• • •
A[0][C-1]
•
•
•
A[R-1][0] • • • A[R-1][C-1]
int A[R][C];
A
A
A
A
[0] • • • [0] [1] • • • [1]
[0]
[C-1] [0]
[C-1]
4*R*C Bytes
•
•
•
A
A
[R-1] • • • [R-1]
[0]
[C-1]
Estruturas Heterogêneas (structs)
O alinhamento de structs na memória segue as regras:
1. Os campos são alocados na ordem em que aparecem
na declaração;
2. Cada campo do struct que corresponde a uma palavra
(ou múltiplas palavras) deve ser alocado em um
endereço múltiplo de 4; shorts em múltiplos de 2
3. O início de cada estrutura tem que estar sempre
alinhado em endereços múltiplos de 4
Exemplo:
struct s{
sizeof(s1) = 8;
char c[2];
int i;
}
Ocupação dos bytes:
c[0]
x
c[1]
struct s s1;
i
Padding =
X+4
bytes não usados
i
i
i
Padding no final
• Para garantir o alinhamento do struct em um endereço
múltiplo de 4, pode ocorrer um padding no final.
• Exemplo:
struct s{
int i;
char c[2];
}
sizeof(h) = 16;
struct s h[2];
h[0]
i
i
i
i
x
h[1]
c[1]
X+4
i
x+8
c[0]
i
i
i
c[0]
X+12
c[1]
Exemplo de Alinhamento de structs
struct s{
char c,d;
int a;
char e
}
struct s s1;
c d
x
a a a
struct s{
short c,d;
char e;
short a
}
struct s s2;
a e
X+4
sizeof(s1) = 12
X+8
c c d d e
x
X+4
sizeof(s2) = 8
a
a
X+8
Download

Representação de Dados - PUC-Rio