gcc -Wall -m32 -o <nome do arquivo executavel> <nome do arquivo fonte>Exemplo:
gcc -Wall -m32 -o dump1 dump1.c
A rotina abaixo faz um "dump" de uma região de memória:
#include <stdio.h> void dump (void *p, int n) { unsigned char *p1 = p; while (n--) { printf("%p - %02x\n", p1, *p1); p1++; } }O dump mostra uma sequência de posições da memória, mostrando para cada posição seu endereço e seu conteúdo (em hexa-decimal). O parâmetro
p
é o endereço inicial a ser mostrado,
e n
é o número de bytes.
Um exemplo de uso é o programa abaixo, que mostra como um inteiro é armazenado na memória:
int main (void) { int i = 10000; dump(&i, sizeof(i)); return 0; }
Explique detalhadamente o resultado do programa acima (se necessário,
rode o programa com outros valores para i
).
Aplique a mesma técnica para ver como um char
é armazenado.
Aplique a mesma técnica para ver como um short
é armazenado.
A mesma técnica pode ser usada para vermos como uma string é armazenada:
int main (void) { char p[] = "7509"; dump(p, sizeof(p)); return 0; }Modifique o exemplo acima para descobrir os códigos ASCII dos caracteres
'a'
,
' '
,
'\0'
,
e '$'
.
Considere a função abaixo, para multiplicar dos números inteiros:
int mul (int a, int b) { int p = 0; while (b) { if (b%2 == 1) p += a; a *= 2; b /= 2; } return p; }Na forma apresentada acima, a função
mul
não faz
muito sentido,
pois usamos várias multiplicações e divisões para simular uma
única multiplicação.
Entretanto, como essas operações são todas com 2,
podemos substituí-las por operadores bit-a-bit,
que são bem mais eficientes.
Reescreva a função mul
de modo que ela não use nenhuma
operação "complicada"
(*
, /
ou %
).
Considere um protocolo que usa um "pacote" de 32 bits de informação com o seguinte formato:
BITS: | 31 - 27 | 26 - 20 | 19 - 16 | 15 | 14 | 13 | 12 | 11 - 0 |
CONTEÚDO: | num. sequencia | fill | versão | f1 | f2 | f3 | prioridade | informação |
Escreva funções em C para realizar as manipulações descritas a seguir. Todas as funções recebem um "pacote" armazenado em um int.
int getVersao (unsigned int pacote)
int isPrio(unsigned int pacote)
unsigned int incrSeq(unsigned int pacote)
Você pode testar as suas funções com o programa abaixo (pode também imaginar outros testes...)
int main() { unsigned int pacote1 = 0x2AAAAAAA; unsigned int pacote2 = 0xFAA5BAAA; unsigned int novopacote; printf("pac1 com seq incrementado\n"); novopacote = incrSeq(pacote1); dump(&novopacote, sizeof(novopacote)); printf("pac2 com seq incrementado\n"); novopacote = incrSeq(pacote2); dump(&novopacote, sizeof(novopacote)); printf("prio pac1 = %s\n", isPrio(pacote1) ? "S" : "N"); printf("prio pac2 = %s\n", isPrio(pacote2) ? "S" : "N"); printf("versão pac1 = %d\n", getVersao(pacote1)); printf("versão pac2 = %d\n", getVersao(pacote2)); return 0; }
void formatArray (unsigned int origem[], unsigned char *dest, int tam)
Você pode usar aqui também a função "dump" para testar, exibindo o "dump" do array original, e a sequencia de inteiros formatada na memória:
#define TAM 3 #define NBYTES TAM * sizeof(unsigned int) int main() { unsigned int array[TAM] = {1, 0xff0102aa, 0x04030201}; unsigned char seq[NBYTES]; formatArray(array, seq, TAM); printf("array na memoria\n"); dump(array, NBYTES); printf("sequencia formatada\n"); dump(seq, NBYTES); return 0; }
Extra: como você deveria modificar sua função para que fosse portátil, isto é, para que funcionasse corretamente tanto em máquinas "big endian" como "little endian"? (você pode usar uma função auxiliar que verifique o tipo de ordenação...)