Flavio58
24-04-2007, 11.00.55
Quando si vuole gestire l'ottica dei puntatori si deve avere sempre a mente che in effetti i dati sono memorizzati in certe locazioni di memoria e che a seconda dei tipi questi tengono un certo numero di bytes.
Un puntatore è come una variabile normale ma solo che il valore che contiene è un indirizzo di un altra locazione di memoria dove viene mantenuto un valore di un ceryo tipo.
In genere quando si cedono cose del tipo :
char *c;
int *c;
struct abc *c;
uno si chiede : ma se un puntatore è uno spazio sufficente a contenere un indirizzo cosa me ne frega di scrivere int *, char * ecc. visto che alla fine gli indirizzi sono sempre lunghi uguale ?
Perchè il tipo dice al sistema che il dato a quell'indirizzo è di un certo tipo e quindi occupa N bytes.
La tipologia influsice sull'aritmetica dei punatori.
In pratica se io avessi :
int *n = (int *) 0x00000C000;
e se poi incrementassi l'indirizzo cosi :
++n;
Di quanti bytes verrebbe incrementato n ?
Semplicemente di :
n = n + (1 * sizeof(int));
ovvero, nel caso di int = 4 bytes, di 4 bytes appunto !
L'aritmetica dei punatori è potente.
Prendete ad esempio il problema di copiare 10 bytes di un array in un altro array.
Norlamente tutti farebbero :
int a[10] = { 1,2,3,4,5,6,7,8,9,0 };
int b[10];
int x;
for(x=0;x!=10;i++)
b[x] = a[x];
Con i punatori potrei fare un codice, che se andate a vederlo in assembler tradotto dal compilatore, molto piu' compatto :
int a[10] = { 1,2,3,4,5,6,7,8,9,0 };
int b[10];
struct x { int a[10]; }; // Solo definizione -- NON DICHIRAZIONE
(*((struct x * )(&b[0]))) = (*((struct x * )(&a[0])));
o
(*((struct x * )(b))) = (*((struct x * )(a)));
Uno comunque potrebbe chiedersi perchè dover usare costrutti come quello di prima e non il semplice ciclo.
Ottimizzazione velocità ....
Se uno scrive gestionale certi tipi di ottimizzazioni può anche evitarle...se invece fai sistemi di compuetr vision allora tutto quello che ottimizza diventa necessario.....
GUarda qui ad esempio :
int a[5] = { 1,2,3,4,5 };
int b[5];
void copia(void)
{
struct p { int f[5]; };
(*((struct p *)(b))) = (*((struct p *)(a)));
}
tradotto dal compilatore con l'opzione Fa
TITLE test1.c
.386P
include listing.inc
if @Version gt 510
.model FLAT
else
_TEXT SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT ENDS
_DATA SEGMENT DWORD USE32 PUBLIC 'DATA'
_DATA ENDS
CONST SEGMENT DWORD USE32 PUBLIC 'CONST'
CONST ENDS
_BSS SEGMENT DWORD USE32 PUBLIC 'BSS'
_BSS ENDS
_TLS SEGMENT DWORD USE32 PUBLIC 'TLS'
_TLS ENDS
FLAT GROUP _DATA, CONST, _BSS
ASSUME CS: FLAT, DS: FLAT, SS: FLAT
endif
PUBLIC _a
_DATA SEGMENT
COMM _b:DWORD:05H
_a DD 01H
DD 02H
DD 03H
DD 04H
DD 05H
_DATA ENDS
PUBLIC _copia
_TEXT SEGMENT
_copia PROC NEAR
; File test1.c
; Line 6
push ebp
mov ebp, esp
push esi
push edi
; Line 8
mov ecx, 5
mov esi, OFFSET FLAT:_a
mov edi, OFFSET FLAT:_b
rep movsd
; Line 9
pop edi
pop esi
pop ebp
ret 0
_copia ENDP
_TEXT ENDS
END
int a[5] = { 1,2,3,4,5 };
int b[5];
int i;
void copia(void)
{
for(i=0;i!=5;i++)
b[i] = a[i];
} TITLE test2.c
.386P
include listing.inc
if @Version gt 510
.model FLAT
else
_TEXT SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT ENDS
_DATA SEGMENT DWORD USE32 PUBLIC 'DATA'
_DATA ENDS
CONST SEGMENT DWORD USE32 PUBLIC 'CONST'
CONST ENDS
_BSS SEGMENT DWORD USE32 PUBLIC 'BSS'
_BSS ENDS
_TLS SEGMENT DWORD USE32 PUBLIC 'TLS'
_TLS ENDS
FLAT GROUP _DATA, CONST, _BSS
ASSUME CS: FLAT, DS: FLAT, SS: FLAT
endif
PUBLIC _a
_DATA SEGMENT
COMM _b:DWORD:05H
COMM _i:DWORD
_a DD 01H
DD 02H
DD 03H
DD 04H
DD 05H
_DATA ENDS
PUBLIC _copia
_TEXT SEGMENT
_copia PROC NEAR
; File test2.c
; Line 6
push ebp
mov ebp, esp
; Line 7
mov DWORD PTR _i, 0
jmp SHORT $L35
$L36:
mov eax, DWORD PTR _i
add eax, 1
mov DWORD PTR _i, eax
$L35:
cmp DWORD PTR _i, 5
je SHORT $L37
; Line 8
mov ecx, DWORD PTR _i
mov edx, DWORD PTR _i
mov eax, DWORD PTR _a[edx*4]
mov DWORD PTR _b[ecx*4], eax
jmp SHORT $L36
$L37:
; Line 9
pop ebp
ret 0
_copia ENDP
_TEXT ENDS
END
Un puntatore è come una variabile normale ma solo che il valore che contiene è un indirizzo di un altra locazione di memoria dove viene mantenuto un valore di un ceryo tipo.
In genere quando si cedono cose del tipo :
char *c;
int *c;
struct abc *c;
uno si chiede : ma se un puntatore è uno spazio sufficente a contenere un indirizzo cosa me ne frega di scrivere int *, char * ecc. visto che alla fine gli indirizzi sono sempre lunghi uguale ?
Perchè il tipo dice al sistema che il dato a quell'indirizzo è di un certo tipo e quindi occupa N bytes.
La tipologia influsice sull'aritmetica dei punatori.
In pratica se io avessi :
int *n = (int *) 0x00000C000;
e se poi incrementassi l'indirizzo cosi :
++n;
Di quanti bytes verrebbe incrementato n ?
Semplicemente di :
n = n + (1 * sizeof(int));
ovvero, nel caso di int = 4 bytes, di 4 bytes appunto !
L'aritmetica dei punatori è potente.
Prendete ad esempio il problema di copiare 10 bytes di un array in un altro array.
Norlamente tutti farebbero :
int a[10] = { 1,2,3,4,5,6,7,8,9,0 };
int b[10];
int x;
for(x=0;x!=10;i++)
b[x] = a[x];
Con i punatori potrei fare un codice, che se andate a vederlo in assembler tradotto dal compilatore, molto piu' compatto :
int a[10] = { 1,2,3,4,5,6,7,8,9,0 };
int b[10];
struct x { int a[10]; }; // Solo definizione -- NON DICHIRAZIONE
(*((struct x * )(&b[0]))) = (*((struct x * )(&a[0])));
o
(*((struct x * )(b))) = (*((struct x * )(a)));
Uno comunque potrebbe chiedersi perchè dover usare costrutti come quello di prima e non il semplice ciclo.
Ottimizzazione velocità ....
Se uno scrive gestionale certi tipi di ottimizzazioni può anche evitarle...se invece fai sistemi di compuetr vision allora tutto quello che ottimizza diventa necessario.....
GUarda qui ad esempio :
int a[5] = { 1,2,3,4,5 };
int b[5];
void copia(void)
{
struct p { int f[5]; };
(*((struct p *)(b))) = (*((struct p *)(a)));
}
tradotto dal compilatore con l'opzione Fa
TITLE test1.c
.386P
include listing.inc
if @Version gt 510
.model FLAT
else
_TEXT SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT ENDS
_DATA SEGMENT DWORD USE32 PUBLIC 'DATA'
_DATA ENDS
CONST SEGMENT DWORD USE32 PUBLIC 'CONST'
CONST ENDS
_BSS SEGMENT DWORD USE32 PUBLIC 'BSS'
_BSS ENDS
_TLS SEGMENT DWORD USE32 PUBLIC 'TLS'
_TLS ENDS
FLAT GROUP _DATA, CONST, _BSS
ASSUME CS: FLAT, DS: FLAT, SS: FLAT
endif
PUBLIC _a
_DATA SEGMENT
COMM _b:DWORD:05H
_a DD 01H
DD 02H
DD 03H
DD 04H
DD 05H
_DATA ENDS
PUBLIC _copia
_TEXT SEGMENT
_copia PROC NEAR
; File test1.c
; Line 6
push ebp
mov ebp, esp
push esi
push edi
; Line 8
mov ecx, 5
mov esi, OFFSET FLAT:_a
mov edi, OFFSET FLAT:_b
rep movsd
; Line 9
pop edi
pop esi
pop ebp
ret 0
_copia ENDP
_TEXT ENDS
END
int a[5] = { 1,2,3,4,5 };
int b[5];
int i;
void copia(void)
{
for(i=0;i!=5;i++)
b[i] = a[i];
} TITLE test2.c
.386P
include listing.inc
if @Version gt 510
.model FLAT
else
_TEXT SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT ENDS
_DATA SEGMENT DWORD USE32 PUBLIC 'DATA'
_DATA ENDS
CONST SEGMENT DWORD USE32 PUBLIC 'CONST'
CONST ENDS
_BSS SEGMENT DWORD USE32 PUBLIC 'BSS'
_BSS ENDS
_TLS SEGMENT DWORD USE32 PUBLIC 'TLS'
_TLS ENDS
FLAT GROUP _DATA, CONST, _BSS
ASSUME CS: FLAT, DS: FLAT, SS: FLAT
endif
PUBLIC _a
_DATA SEGMENT
COMM _b:DWORD:05H
COMM _i:DWORD
_a DD 01H
DD 02H
DD 03H
DD 04H
DD 05H
_DATA ENDS
PUBLIC _copia
_TEXT SEGMENT
_copia PROC NEAR
; File test2.c
; Line 6
push ebp
mov ebp, esp
; Line 7
mov DWORD PTR _i, 0
jmp SHORT $L35
$L36:
mov eax, DWORD PTR _i
add eax, 1
mov DWORD PTR _i, eax
$L35:
cmp DWORD PTR _i, 5
je SHORT $L37
; Line 8
mov ecx, DWORD PTR _i
mov edx, DWORD PTR _i
mov eax, DWORD PTR _a[edx*4]
mov DWORD PTR _b[ecx*4], eax
jmp SHORT $L36
$L37:
; Line 9
pop ebp
ret 0
_copia ENDP
_TEXT ENDS
END