PDA

View Full Version : Stampare l'indirizzo dei 4 byte allocati per un intero in C senza cast @ (char*)


swarzy85
23-07-2005, 12:16
Ciao :)
come da titolo, mi interessa sapere come fare per riuscire a stampare gli indirizzi dei 4 byte consecutivi allocati per un intero, senza utilizzare il cast @ (char*).

Esempio con cast (solo estratto di un programma...giusto per dare un'idea):

int i, v[5];

for (i=0; i<5; i++)
{
v[i]=i;
printf ("%d %d %d %d", (char*)&v[i]+3, (char*)&v[i]+2, (char*)&v[i]+1, (char*)&v[i]);
}


Senza cast non riesco a farlo...
Scrivendo soltanto v, si ottiene un puntatore costante al primo byte del vettore v.

Ovviamente, se scrivo v+1, verrà esseguita una conversione di tipo e, se sto cercando di stampare il secondo byte dell'intero salvato in v[0], avrò stampato in realtà l'indirizzo di v[1] dato che salterà di 4 byte in 4 byte.

Devo riuscire a stampare i 4 byte corretti per ogni intero, senza usare il cast.

Help

fek
23-07-2005, 12:46
int address = &v[i]; // cast implicito
printf("%d %d %d %d", address + 3, address + 2, address + 1, address);

swarzy85
23-07-2005, 13:26
Ciao Francesco :)

ho provato a riscrivere velocemente il programma (era il primo esonero di fondamenti 2 da correggere....in pratica mancavano diversi puntatori e ce n'erano altri messi a caso)

#include <stdio.h>
#include <malloc.h>

void alloc (int **, int);
void setta (int *, int);
void stampa_su_file (int*, int);


void main ()
{
int n;
int *v=NULL;

printf ("Inserire il numero di elementi: ");
scanf ("%d", &n);
alloc (&v, n);
setta (v, n);
stampa_su_file (v, n);
free (v);
}

void alloc (int **v, int n)
{
*v = (int*) malloc (n * sizeof (int));
}

void setta (int *v, int n)
{
int i;
for (i=0; i<n; i++)
v[i] = i;
}

void stampa_su_file (int *v, int n)
{
FILE *fp;
int i, address;

fp = fopen ("uscita.txt", "w");

for (i=0; i<n; i++)
{
address = &v[i];
fprintf (fp, "v[%d] che si trova ai byte numero %d %d %d %d vale = %d\n", i, address+3, address+2, address+1, address, i);
}
fclose (fp);
}

Ho fatto come mi hai consigliato e funziona perfettamente :)
Ieri avevo provato a fare la stessa cosa ma mi dava un errore in compilazione...
appena ho provato a fare ciò che mi hai indicato, mi ha dato il medesimo errore...
in pratica lo compilavo in C++ :(

Grazie ancora :)

fek
23-07-2005, 14:10
Ciao Francesco :)


Ciao :)

appena ho provato a fare ciò che mi hai indicato, mi ha dato il medesimo errore...
in pratica lo compilavo in C++ :(

Grazie ancora :)

Era un errore oppure un warning? Perche' trattare un puntatore come un intero in C++ e' una cosa che non andrebbe mai fatta e molti compilatori lo segnalano con un warning.

Ma perche' vi insegnano cose come queste all'Universita'? Fa il paio con i lucidi che usano i float come parametri per un template.

Fenomeno85
23-07-2005, 14:24
Ciao :)



Era un errore oppure un warning? Perche' trattare un puntatore come un intero in C++ e' una cosa che non andrebbe mai fatta e molti compilatori lo segnalano con un warning.

Ma perche' vi insegnano cose come queste all'Universita'? Fa il paio con i lucidi che usano i float come parametri per un template.

guarda che i puntatori si possono tranquillamente usare come "interi" cioè sommando ... è l'algebra dei puntatori ed è impossibile che dia warning


~§~ Sempre E Solo Lei ~§~

cionci
23-07-2005, 14:47
guarda che i puntatori si possono tranquillamente usare come "interi" cioè sommando ... è l'algebra dei puntatori ed è impossibile che dia warning

Il problema non era l'utilizzo come interi, ma il casting implicito che in C++ va esplicitato...mentre in C funziona senza problemi...

repne scasb
23-07-2005, 14:49
A meno di errori grossolani:


int i, v[5];

for (i=0; i<5; i++)
printf ("%d %d %d %d\n",++v[i]+(v[i]=i)-i,++v[i],++v[i],v[i]=&v[i]);


NOTE: a) L'esecuzione del codice nella printf si legge da destra verso sinistra.
b) v[i]=i, e' implicitamente assegnato al termine dei "push" sulla printf.

fek
23-07-2005, 15:34
A meno di errori grossolani:


int i, v[5];

for (i=0; i<5; i++)
printf ("%d %d %d %d\n",++v[i]+(v[i]=i)-i,++v[i],++v[i],v[i]=&v[i]);


NOTE: a) L'esecuzione del codice nella printf si legge da destra verso sinistra.
b) v[i]=i, e' implicitamente assegnato al termine dei "push" sulla printf.

Lo Standard C++ non da' garanzie sull'ordine di valutazione degli argomenti di una chiamata a funzione. Questo codice e' "Undefined" in C++.

Non ricordo a memoria se lo Standard del C da' garanzia sull'ordine di valutazione (mi sembrerebbe molto strano se lo facesse).

repne scasb
23-07-2005, 17:36
Lo Standard C++ non da' garanzie sull'ordine di valutazione degli argomenti di una chiamata a funzione. Questo codice e' "Undefined" in C++.

Non ricordo a memoria se lo Standard del C da' garanzia sull'ordine di valutazione (mi sembrerebbe molto strano se lo facesse).

Il passaggio dei parametri puo' avvenire da destra verso sinistra da sinistra verso destra, con allineamento dello stack a carico del chiamante o del chiamato, per registro, o in altri modi piu' o meno esotici.

I due metodi piu' utilizzati sono da destra a sinistra con stack a carico del chiamante, e da sinistra a destra con stack a carico del chiamato. Il secondo metodo si chiama "passaggio di paramentri con convenzione pascal", il primo "standard C". Ci sarebbe da verificare se il primo metodo chiamato "standard C" e' in effetti uno standard del C.

Nonostante cio', esiste comunque la possibilita' di verificare all'interno del codice stesso la modalita' di passaggio dei paramentri sullo stack:


{
a=0;
a=func(a--,a++)
if(a>0)
printf("Da destra a sinistra\n");
else
printf("Da sinistra a destra\n");
}

func(int a,int b)

{
return(a+b);
}


Quindi nel nostro caso (sempre a meno di errori grossolani):


{
int i, v[5];
a=0;

a=func(a--,a++)
if(a>0)
printf ("%d %d %d %d\n",++v[i]+(v[i]=i)-i,++v[i],++v[i],v[i]=&v[i]);
else
printf ("%d %d %d %d\n",v[i]=&v[i],++v[i],++v[i],++v[i]+(v[i]=i)-i);
}

func(int a,int b)

{
return(a+b);
}

swarzy85
23-07-2005, 19:33
Ciao :)

Era un errore oppure un warning? Perche' trattare un puntatore come un intero in C++ e' una cosa che non andrebbe mai fatta e molti compilatori lo segnalano con un warning.

Ma perche' vi insegnano cose come queste all'Universita'? Fa il paio con i lucidi che usano i float come parametri per un template.
Era proprio un errore Francesco :) (il succo era che non poteva convertire un int* in int)
Uso Visual Studio 6.0 come compilatore.

Perchè ci insegnano queste cose? Veramente non ce le hanno insegnate :)
Per la fine del corso bisognava portare un programma intero in C++ su un argomento a scelta (tra 6 proposti).
Io ho portato un software di gestione aziendale...erano circa 2000 righe di codice; diciamo che ho imparato un sacco di cose (soprattutto l'utilità delle STL in certe occasioni).

Poi, però, all'orale venivano fatte altre domande...domande tipo quella che ho posto io qui.
A me è stato chiesto di stampare gli indirizzi di un intero e l'ho fatto con il cast @ char*.
Poi mi è stato chiesto di farlo senza cast e all'inizio ho detto una cavolata immane. Allora, mentre veniva interrogato un altro ragazzo, dovevo provare a trovare una soluzione. Ho commesso l'errore grossolano di creare un .cpp e quindi mi restituiva errore; di conseguenza, quando il professore mi ha chiesto a che punto fossi, ho risposto che non ero riuscito a combinare nulla.

swarzy85
23-07-2005, 19:38
Il problema non era l'utilizzo come interi, ma il casting implicito che in C++ va esplicitato...mentre in C funziona senza problemi...
esatto, dovrebbe essere una situazione analoga a quella che si presenta quando si usa la malloc in C e in C++ (nel primo caso non serve il cast, nel secondo è necessaria....infatti io avevo scritto un .cpp):
*v = (int*) malloc (n * sizeof (int));

fek
23-07-2005, 19:39
Il passaggio dei parametri puo' avvenire da destra verso sinistra da sinistra verso destra, con allineamento dello stack a carico del chiamante o del chiamato, per registro, o in altri modi piu' o meno esotici.

No. Standard C++ alla mano, anche questo codice e' illegale, perche' la valutazione dei parametri e il loro passaggio dei possono essere in qualunque ordine, anche del tutto casuale, per lasciare al compilatore il totale controllo sull'ottimizzazione. Il compilatore e' libero di valutare i parametri per la stessa chiamata da sinistra verso destgra una volta, da destra verso sinistra la seconda volta, o in qualunque ordine gli aggrada anche all'interno dello stesso programma.

Qualunque codice il cui corretto funzionamento dipende da una particolare assunzione sull'ordine di valutazione e' "Undefined" e non e' C++.

http://www.gotw.ca/gotw/012.htm


int f( int& x, int y = x ) { return x += y; }
int g( int& x ) { return x /= 2; }

int main( int, char*[] ) {
int i = 42;
cout << "f(" << i << ") = " << f(i) << ", "
<< "g(" << i << ") = " << g(i) << endl;


Here we run into parameter evaluation ordering again. Since there's no telling the order in which f(i) or g(i) will be executed (or, for that matter, the ordering of the two bald evaluations of 'i' itself), the printed results can be quite incorrect. One example result is MSVC's "f(22) = 22, g(21) = 21", which means the compiler is likely evaluating all function arguments in order from right to left.

But isn't the result wrong? No, the compiler is right... and another compiler could print out something else and still be right, too, because the programmer is relying on something that is undefined in C++.

swarzy85
23-07-2005, 19:40
A meno di errori grossolani:


int i, v[5];

for (i=0; i<5; i++)
printf ("%d %d %d %d\n",++v[i]+(v[i]=i)-i,++v[i],++v[i],v[i]=&v[i]);


NOTE: a) L'esecuzione del codice nella printf si legge da destra verso sinistra.
b) v[i]=i, e' implicitamente assegnato al termine dei "push" sulla printf.
Ciao :)
grazie per l'informazione, non conoscevo l'ordine di lettura della printf :)

Riguardo la tua soluzione:
secondo il tuo ragionamento, visto che la lettura avviene da destra verso sinistra assegni a v[i] il suo indirizzo. In tal modo ti basta incrementare di 1 l'indirizzo con la notazione prefissa del "++".
Quando viene stampato l'ultimo byte (...il primo nella printf), però, perchè incrementi il valore dell'inidirzzo di 1 e aggiungi e sottrai i?

P.S. adesso lo provo :)

fek
23-07-2005, 19:41
Ciao :)
grazie per l'informazione, non conoscevo l'ordine di lettura della printf :)


E continui a non conoscerlo perche' l'ordine e' indefinito e dipende da compilatore a compilatore :)

swarzy85
23-07-2005, 19:46
E continui a non conoscerlo perche' l'ordine e' indefinito e dipende da compilatore a compilatore :)
Mhmhm capito :)
ora provo a vedere cosa succede con il Visual Studio.
Comunque volevo chiederti un'altra cosa: non è possibile trovare una soluzione senza appoggiarsi ad un intero (per fargli salvare l'indirizzo)? In pratica, mi chiedo se si potrebbe ottenere un risultato analogo usando nella fprintf solo l'operatore + per fargli eseguire un cast implicito?

Te lo domando perchè il professore ha provato a darmi un imput dicendomi che in C viene eseguita una conversione di tipo automatica quando si usa l'operatore + in un certo modo.
Sinceramente non riesco a trovare altre soluzioni a parte quella che mi hai indicato tu :(

swarzy85
23-07-2005, 19:49
In questo modo funziona:
fprintf (fp, "v[%d] che si trova ai byte numero %d %d %d %d vale = %d\n", i, ++v[i], ++v[i], ++v[i], v[i]=&v[i], i);

fek
23-07-2005, 19:51
Te lo domando perchè il professore ha provato a darmi un imput dicendomi che in C viene eseguita una conversione di tipo automatica quando si usa l'operatore + in un certo modo.
Sinceramente non riesco a trovare altre soluzioni a parte quella che mi hai indicato tu :(

Hmmm... Francamente non riesco ad immaginare in quale modo potrebbe essere usato l'operatore + per causare un cast implicito a int di un puntatore :)

fek
23-07-2005, 19:52
In questo modo funziona:
fprintf (fp, "v[%d] che si trova ai byte numero %d %d %d %d vale = %d\n", i, ++v[i], ++v[i], ++v[i], v[i]=&v[i], i);

Non e' C/C++ per il motivo di prima. Il risultato e' "Undefined" e dipende dal compilatore/giorno della settimana/tempo atmosferico.

swarzy85
23-07-2005, 19:56
Non e' C/C++ per il motivo di prima. Il risultato e' "Undefined" e dipende dal compilatore/giorno della settimana/tempo atmosferico.
Si si, ho capito, tranquillo :)

Si vede che sbatterò la testa contro il muro finchè non troverò un'altra soluzione :D (o finchè il muro non sarà diventato tutto rosso) :D

P.S. stamattina non avevo niente da fare e ho scaricato alcuni file .cpp. Ho visto delle librerie tipo dos.h, windows.h e winsock.h che mi ispirano parecchio :mc:
Partendo dal presupposto che la programmazione non mi piace nemmeno un pò...sta diventando una sfida personale :)

repne scasb
23-07-2005, 20:51
No. Standard C++ alla mano............

Non sto parlando di C++ in quanto il messaggio d'aiuto originario chiede: "Stampare l'indirizzo dei 4 byte allocati per un intero in C senza cast @" e non si fa alcun cenno di C++. La mia risposta e' quindi strettamente attinente a quanto chiesto. Se ne deduce che il codice piu' sopra inviato non e' C++ ma C (per la precisione e' C--).

repne scasb
23-07-2005, 21:44
Si si, ho capito, tranquillo :)

Si vede che sbatterò la testa contro il muro finchè non troverò un'altra soluzione

Altra soluzione:


int i, v[5],*a;

a=0;
for (i=0; i<5; i++)
{
v[i]=i;
printf ("%d %d %d %d\n",((v-a)<<(sizeof(int)>>1))+i+3,((v-a)<<(sizeof(int)>>1))+i+2,((v-a)<<(sizeof(int)>>1))+i+1,((v-a)<<(sizeof(int)>>1))+i);
}


Si basa sul concetto che una differenza di puntatori e' equivalente al numero di elementi puntati dal puntatore

fek
23-07-2005, 21:55
Non sto parlando di C++ in quanto il messaggio d'aiuto originario chiede: "Stampare l'indirizzo dei 4 byte allocati per un intero in C senza cast @" e non si fa alcun cenno di C++. La mia risposta e' quindi strettamente attinente a quanto chiesto. Se ne deduce che il codice piu' sopra inviato non e' C++ ma C (per la precisione e' C--).

Ho controllato, quel codice e' indefinito anche in C.

repne scasb
23-07-2005, 22:16
Ho controllato, quel codice e' indefinito anche in C.

Hai le idee confuse.

Se in C o "altro" non fosse definito il modo con cui il compilatore passa i paramentri di una funzione attraverso lo stack non sarebbe possibile agganciarci una subroutine in assembly, in quanto non saprei dove prelevare sullo stack quello che mi sta passando il compilatore. Ossia:

[CODE]
func(a,b,c)...

mov eax,[ebp-???] ; a
mov ebx,[ebp-???] ; b
mov ecx,[ebp-???] ; c
[

Se non so che sta facendo il compilatore come mi aggancio? Basta sepere cosa sta facendo il compilatore. In pascal o modula 2, li passa da sinistra a destra e non riallinea lo stack (devo farlo io a mano con un retn nn); in C o C++ li passa da destra verso sinistra e riallinea lo stack; in vbasic li passa da sinistra verso destra e riallinea lo stack, ecc, ecc.

Ossia cambia in generale da linguaggio a linguaggio, ma una volta che il compilatore ha "deciso" come passare i paramentri di una funzione li adotta sempre ed ovunque. Quest'ultima affermazione pero' potrebbe avere qualche eccezzione, dovresti quindi essere cosi' gentile da indicarmi quale compilatore varia l'ordine di passaggio dei dati attraverso lo stack all'interno di uno stesso codice in modo che possa effettuare alcune verifiche (in 25 anni di programmazione assembly non ho mai visto nulla di simile e sono disponibile ad imparare cose nuove).

okay
23-07-2005, 22:41
Hai le idee confuse.

Se in C o "altro" non fosse definito il modo con cui il compilatore passa i paramentri di una funzione attraverso lo stack non sarebbe possibile agganciarci una subroutine in assembly, in quanto non saprei dove prelevare sullo stack quello che mi sta passando il compilatore. Ossia:

[CODE]
func(a,b,c)...

mov eax,[ebp-???] ; a
mov ebx,[ebp-???] ; b
mov ecx,[ebp-???] ; c
[

Se non so che sta facendo il compilatore come mi aggancio? Basta sepere cosa sta facendo il compilatore. In pascal o modula 2, li passa da sinistra a destra e non riallinea lo stack (devo farlo io a mano con un retn nn); in C o C++ li passa da destra verso sinistra e riallinea lo stack; in vbasic li passa da sinistra verso destra e riallinea lo stack, ecc, ecc.

Ossia cambia in generale da linguaggio a linguaggio, ma una volta che il compilatore ha "deciso" come passare i paramentri di una funzione li adotta sempre ed ovunque. Quest'ultima affermazione pero' potrebbe avere qualche eccezzione, dovresti quindi essere cosi' gentile da indicarmi quale compilatore varia l'ordine di passaggio dei dati attraverso lo stack all'interno di uno stesso codice in modo che possa effettuare alcune verifiche (in 25 anni di programmazione assembly non ho mai visto nulla di simile e sono disponibile ad imparare cose nuove).










ciao

sono OT ma:

sono proprio contento di rileggerti................ sei veramente clamorosa.
Non sò se hai risposto al mio msg privato (ora controllo) ma ho questa curiosità da molto tempo (direi anni è da poco che mi sono riaffacciato quì) ti chiedo se stai lavorando nel campo della programmazione...... se si per quale progetto.

ciao da okay

fek
23-07-2005, 22:54
Hai le idee confuse.

Se in C o "altro" non fosse definito il modo con cui il compilatore passa i paramentri di una funzione attraverso lo stack non sarebbe possibile agganciarci una subroutine in assembly, in quanto non saprei dove prelevare sullo stack quello che mi sta passando il compilatore

Le mie idee sono molto chiare. Ne' in C ne' in C++ lo standard definisce l'ordine di valutazione dei parametri, che e' lasciato libero al compilatore. Da notare che l'ordine di valutazione dei parametri e' una cosa ben diversa dall'ordine di passaggio dei valori sullo stack (concetto irrilevante ai fini della discussione), anch'esso non definito dallo standard, tanto e' vero che il compilatore e' libero di passare i valori per registri se lo reputa necessario. Sei tu che stai facendo confusione fra i due concetti.

Il concetto da esprimere qui e' che il codice da te riportato non e' codice C ne' C++ valido, ma il risultato e' indefinito, perche' ogni compilatore e' libero di decidere l'ordine di valutazione dei parametri.

Ho riportato un link che porta alcuni esempi di chiariscono il discorso.

Infine per quanto la cosa possa sembrarti strana e impossibile, non sono stato io a scrivere lo standard C e C++ e non e' colpa mia se il linguaggio non stabilisce ne' l'ordine di valutazione dei parametri ne' la topologia dello stack frame. Il codice che hai riportato non e' ne' C ne' C++, il suo risultato e' "Undefined".

Puoi trovare ulteriori informazioni leggendo i due Standard.

Quest'ultima affermazione pero' potrebbe avere qualche eccezzione, dovresti quindi essere cosi' gentile da indicarmi quale compilatore varia l'ordine di passaggio dei dati attraverso lo stack all'interno di uno stesso codice in modo che possa effettuare alcune verifiche (in 25 anni di programmazione assembly non ho mai visto nulla di simile e sono disponibile ad imparare cose nuove).

Avendo ben presente che ordine di valutazione dei parametri e passaggio dei valori alla funzione chiamata (che andrebbe piu' correttamente chiamato "stack frame construction") sono due concetti diversi, rispondo alla tua curiosita'
.
Visual C/C++ (Versione 6, 7 e 8). E' possibile richiedere il passaggio per parametri di una funzione in Pascal order o in ordine inverso. E', inoltre, possibile richiedere il passaggio di alcuni parametri per registri e non nello stack. La scelta puo' essere effettuata per funzione. Queste scelte sono possibili proprio perche' lo Standard non definisce ne' l'ordine di valutazione dei parametri ne' la costruzione dello stack frame, entrambi lasciati come scelte di chi implementa i compilatori.

Come curiosita', COM nasce proprio con lo scopo di standardizzare la costruzione dello stack frame dei metodi virtuali che non e' standard nei compilatori C/C++ per Windows, di modo che un binario compilato "COM compliant" con un compilatore potesse essere consumato da un altro compilatore C/C++, oppure anche da un altro linguaggio "COM aware".

Ultima curiosita': ordine di valutazione e stack frame non sono le sole caratteristiche del C++ lasciate volutamente indefinite dallo Standard. Anche layout in memoria della virtual table ad esempio e' lasciato libero al compilatore (e diversi compilatori la implementano in diversi modi).

71104
23-07-2005, 23:06
Non sto parlando di C++ in quanto il messaggio d'aiuto originario chiede: "Stampare l'indirizzo dei 4 byte allocati per un intero in C senza cast @" e non si fa alcun cenno di C++. La mia risposta e' quindi strettamente attinente a quanto chiesto. Se ne deduce che il codice piu' sopra inviato non e' C++ ma C (per la precisione e' C--). ma in provincia: Jack.

71104
23-07-2005, 23:08
comunque dico la mia: repne scasb, quando hai postato il tuo codice hai semplicemente scordato di specificare che valeva solo per uno specifico tipo di compilatori C. inoltre ti faccio notare che stai continuando ad usare impropriamente l'espressione "allineare lo stack": l'allineamento è una cosa, il mantenimento un'altra. :)

fek
23-07-2005, 23:09
comunque dico la mia: repne scasb, quando hai postato il tuo codice hai semplicemente scordato di specificare che valeva solo per uno specifico tipo di compilatori C. inoltre ti faccio notare che stai continuando ad usare impropriamente l'espressione "allineare lo stack": l'allineamento è una cosa, il mantenimento un'altra. :)

Quel codice e' errato anche in C99. Dovrei controllare in C di K&R.

Direttamente dallo Standard ISO C99:

[#10] The order of evaluation of the function designator,
the actual arguments, and subexpressions within the actual
arguments is unspecified, but there is a sequence point
before the actual call.

[#12] EXAMPLE In the function call

(*pf[f1()]) (f2(), f3() + f4())

the functions f1, f2, f3, and f4 may be called in any order.
All side effects have to be completed before the function
pointed to by pf[f1()] is called.

http://www.open-std.org/jtc1/sc22/open/n2794/n2794.txt

Direi che non c'e' altro da aggiungere sull'argomento.

repne scasb
23-07-2005, 23:29
Non sò se hai risposto al mio msg privato (ora controllo)

No, e mi scuso. Ho sempre meno tempo a disposizione, perfino per rispondere adeguatamente ad un messaggio privato.


ma ho questa curiosità da molto tempo (direi anni è da poco che mi sono riaffacciato quì) ti chiedo se stai lavorando nel campo della programmazione...... se si per quale progetto.


Nel mio tempo libero attualmente a 4 progetti:

a) Un progetto riguardante uno standard di comunicazione per dispositivi digitali a perdita d'informazione isocroni.
b) Un progetto per la definizione di una procedura univoca e certificata per la gestione di eccezioni rischiose in specifici apparati d'uso industriale in condizioni di "fault tolerance".
c) Un modello matematico numerico-geometria/energia nel campo delle grandi molecole.
d) Un sistema ottimale per dare il "resto" in monetine in macchine automatiche (potrebbe non convenire affatto utilizzare il numero minimo di monetine per dare il resto se i tagli di monete non sono multipli interi tra di loro).

repne scasb
23-07-2005, 23:50
Inoltre ti faccio notare che stai continuando ad usare impropriamente l'espressione "allineare lo stack": l'allineamento è una cosa, il mantenimento un'altra.

Per allineamento dello stack non si intende un allineamento in memoria (ALIGN), ma il raggiungimento della posizione in memoria dello stack prima e dopo una chiamata. Ossia:


; riallineamento sul chiamante

push xx
push yy
push zz
call aa
add esp,4*3

--------

aa:
...
...
...
ret

; riallineamento sul chiamato

push xx
push yy
push zz
call aa

--------

aa:
...
...
...
ret 4*3


Per anni si e' parlato di allineamento dello stack in questi termini, poi, come sempre, si e' cambiato il significato delle parole. Per me, comunque, l'allineamento dello stack rimane quello sopra descritto, e non certo l'allocazione in memoria con i primi 'nn' bit dell'indirizzo settati a zero.

repne scasb
24-07-2005, 00:02
Avendo ben presente che ordine di valutazione dei parametri e passaggio dei valori alla funzione chiamata (che andrebbe piu' correttamente chiamato "stack frame construction") sono due concetti diversi, rispondo alla tua curiosita'
.
Visual C/C++ (Versione 6, 7 e 8). E' possibile richiedere il passaggio per parametri di una funzione in Pascal order o in ordine inverso. E', inoltre, possibile richiedere il passaggio di alcuni parametri per registri e non nello stack. La scelta puo' essere effettuata per funzione. Queste scelte sono possibili proprio perche' lo Standard non definisce ne' l'ordine di valutazione dei parametri ne' la costruzione dello stack frame, entrambi lasciati come scelte di chi implementa i compilatori.


Ossia compilatore valuta come gli pare, e passa i paramentri sullo stack da destra a sinistra:

[CODE]
a=0;
func(a++,a--)
[CODE]

quindi sullo stack potrei avere: (-1,0) oppure (0,1) a secondo "degli agenti atmosferici". Tutto cio in visual C++ 6/7/8?

Adesso provo.

fek
24-07-2005, 00:07
quindi sullo stack potrei avere: (-1,0) oppure (0,1) a secondo "degli agenti atmosferici". Tutto cio in visual C++ 6/7/8?


Esattamente. A seconda delle opzioni di compilazione e della dichiarazione della funzione, lo stack frame puo' essere differente.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/html/_core_argument_passing_and_naming_conventions.asp


Keyword Stack cleanup Parameter passing
__cdecl Caller Pushes parameters on the stack, in reverse order (right to left)
__stdcall Callee Pushes parameters on the stack, in reverse order (right to left)
__fastcall Callee Stored in registers, then pushed on stack
thiscall
(not a keyword) Callee Pushed on stack; this pointer stored in ECX


Un esempio di convenzione di chiamata che valuta left to right sono le API Win32:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/html/_core_obsolete_calling_conventions.asp

WINDOWS.H now supports the WINAPI macro, which translates to the appropriate calling convention for the target. Use WINAPI where you previously used PASCAL or __far __pascal.

Ricordo che il Pascal valuta left to right.

Per evitare di farti perdere troppo tempo in prove, ecco una spiegazione semplice delle varie convenzioni di chiamate con il disassemblato dei relativi stack frame generati da Borland C++ 5.5:

http://www.programmers-corner.com/tutorial/16

_cdecl

* Arguments Passed from Right to Left
* Calling Function Clears the Stack
* ‘this’ pointer is passed via stack last in case of Programs using OOP
* Functions using _cdecl are preceded by an “_”

Pascal

* Arguments Passed from Left to Right
* Called Function Clears the Stack

_stdcall

* Arguments Passed from Right to Left
* Called Function Clears the Stack
* ‘this’ pointer passed via Stack Last
* Functions Using _stdcall are preceded by a ‘_’ and end with ‘@’

_fastcall

* Passes Arguments Via Registers. In case of unavailability of registers arguments are passed via the Stack.
* Functions using Fastcall precede with a ‘@’.

repne scasb
24-07-2005, 00:22
Esattamente. A seconda delle opzioni di compilazione e della dichiarazione della funzione, lo stack frame puo' essere differente.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/html/_core_argument_passing_and_naming_conventions.asp


Keyword Stack cleanup Parameter passing
__cdecl Caller Pushes parameters on the stack, in reverse order (right to left)
__stdcall Callee Pushes parameters on the stack, in reverse order (right to left)
__fastcall Callee Stored in registers, then pushed on stack
thiscall
(not a keyword) Callee Pushed on stack; this pointer stored in ECX


Un esempio di convenzione di chiamata che valuta left to right sono le API Win32:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/html/_core_obsolete_calling_conventions.asp


Ricordo che il Pascal valuta left to right.


cdecl e pascal si utilizzano per specificare "come" passare i paramentri sullo stack da destra a sinistra o da sinistra a destra. Ed e' una cosa.

Tu stai dicendo che indipendentemente da cio', il compilatore valuta da destra a sinistra o da sinistra a destra indipendentemente da cdecl o pascal ma a seconda "degli agenti atmosferici".

Ho appenda provato il visual C++ 6.0 Standard Edition con i seguenti codici:


func_1(a++,a--)

func_2(a--,a++)

func_3(b=(b^1)-1,b)

func_4(b=a,b=c)

func_5(*p++,*p--)

func_6(p[i++],p[i--])


Sono tutti implicitamenti cdecl nel passaggio sullo stack. In tutti i casi il compilatore ha valutato "sempre" da destra a sinistra in "accordo" con il passaggio sullo stack.

Puoi farmi un esempio da compilare in VC++ 6 in modo che la valutazione del compilatore sia in disaccordo con il passaggio dei paramentri sullo stack?

repne scasb
24-07-2005, 00:27
Per evitare di farti perdere troppo tempo in prove, ecco una spiegazione semplice delle varie convenzioni di chiamate con il disassemblato dei relativi stack frame generati da Borland C++ 5.5:

http://www.programmers-corner.com/tutorial/16

_cdecl

* Arguments Passed from Right to Left
* Calling Function Clears the Stack
* ‘this’ pointer is passed via stack last in case of Programs using OOP
* Functions using _cdecl are preceded by an “_”

Pascal

* Arguments Passed from Left to Right
* Called Function Clears the Stack

_stdcall

* Arguments Passed from Right to Left
* Called Function Clears the Stack
* ‘this’ pointer passed via Stack Last
* Functions Using _stdcall are preceded by a ‘_’ and end with ‘@’

_fastcall

* Passes Arguments Via Registers. In case of unavailability of registers arguments are passed via the Stack.
* Functions using Fastcall precede with a ‘@’.


Ho lavorato per Borland fino al BC++ 3.1 AeF, e queste cose ho aiutato anch'io a definirle nel 1991. Tutto cio' riguarda come il compilatore passa gli argomenti/parametri (non so come si dice in italiano) sullo stack. Ripeto: tu mi stai dicendo che indipendentemende da questo, il compilatore valuta "a modo suo"?

fek
24-07-2005, 00:28
Tu stai dicendo che indipendentemente da cio', il compilatore valuta da destra a sinistra o da sinistra a destra indipendentemente da cdecl o pascal ma a seconda "degli agenti atmosferici".

Non ho mai detto questo. Ho detto che lo Standard non definisce ne' l'ordine di valutazione ne' lo stack frame ed il compilatore e' libero di scegliere l'ordine. Ti ho anche riportato il passo dello Standard che definisce questo comportamento e dichiara invalido codice la cui correttezza dipende dall'ordine di valutazione (come quello da te postato). Mi sembrava piuttosto chiaro e difficile da fraintendere.


Puoi farmi un esempio da compilare in VC++ 6 in modo che la valutazione del compilatore sia in disaccordo con il passaggio dei paramentri sullo stack?

Ovviamente una volta che il compilatore ha deciso l'ordine di valutazione dei parametri e costruito lo stack frame, genera il codice chiamato in maniera compatibile.

fek
24-07-2005, 00:30
Ho lavorato per Borland fino al BC++ 3.1 AeF, e queste cose ho aiutato anch'io a definirle nel 1991. Tutto cio' riguarda come il compilatore passa gli argomenti/parametri (non so come si dice in italiano) sullo stack. Ripeto: tu mi stai dicendo che indipendentemende da questo, il compilatore valuta "a modo suo"?

No, non ho detto questo, hai frainteso. Per ovvi motivi una volta stabilito l'ordine di valutazione, lo stack frame e' costruito di conseguenza.
Questo non e' comunque rilevante ai fini del discorso.

La soluzione al problema del topic che hai riportato era errata perche' lo Standard non stabilisce l'ordine di valutazione dei parametri, come ho quotato direttamente dallo standard stesso.

repne scasb
24-07-2005, 00:35
Ovviamente una volta che il compilatore ha deciso l'ordine di valutazione dei parametri e costruito lo stack frame, genera il codice chiamato in maniera compatibile.

Ma e' possibile che ci fraintendiamo sempre. Io avevo inteso che definito all'interno del compilatore l'ordine dello stack-frame (cdecl, pascal, register,..) poi il compilatore valutava come gli pareva (da destra, da sinistra, dal centro...).

fek
24-07-2005, 00:37
Ma e' possibile che ci fraintendiamo sempre. Io avevo inteso che definito all'interno del compilatore l'ordine dello stack-frame (cdecl, pascal, register,..) poi il compilatore valutava come gli pareva (da destra, da sinistra, dal centro...).

Possibile che ci fraintendiamo. Non ho detto questo. Sarebbe palesemente sbagliato. Forse non ci crederai, ma anch'io so come si costruiscono gli stack frame ed ho scritto qualche funzioncina asm in carriera :)

Ci troviamo d'accordo allora?
E' chiaro perche' il codice era errato e non era C/C++ Standard?

repne scasb
24-07-2005, 00:53
La soluzione al problema del topic che hai riportato era errata perche' lo Standard non stabilisce l'ordine di valutazione dei parametri, come ho quotato direttamente dallo standard stesso.

a) Non viene definito in standard l'ordine di valutazione.
b) Ti espongo che ho sempre visto l'ordine di valutazione di un compilatore in accordo con il passaggio dei parametri sullo stack; e poiche' in C lo standard e' cdecl (da destra verso sinistra), ho sempre visto/sviluppato compilatori C con valutazione da destra verso sinistra (e' chiaro che se dichiaro una funzione come pascal la cosa cambia).
c) Poiche' non ho mai visto un compilatore valutare i parametri di una funzione in disaccordo con il passaggio dei medesimi sullo stack, ti avevo chiesto un esempio di un compilatore e un codice che avesse tale comportamento.
d) Ora mi dici che il mio esempio era errato perche' lo standard non definisce l'ordine di valutazione dei parametri.
d) Adesso non ti seguo piu'. Mi sono persa.....cosa vuoi dire? Ho compilato il mio esempio in visual c/c++ 6.0 e funziona secondo le aspettative, ossia:

1) Lo standard del passaggio dei paramentri sullo stack e' cdecl.
2) Tranne caso contrario il compilatore compila valutando in accordo con il passaggio dei paramentri sullo stack.
3) Da cui: l'esempio che ho mostrato una volta compilato funziona.
4) Per sostenere la non funzionalita' verrei vedere un esempio di codice che in C venga valutato da sinistra a destra "SENZA" forzatura pascal.

repne scasb
24-07-2005, 00:54
repne scasb, quando hai postato il tuo codice hai semplicemente scordato di specificare che valeva solo per uno specifico tipo di compilatori C.

Quale sarebbe questo tipo "specifico" di compilatori C?

swarzy85
24-07-2005, 09:39
Altra soluzione:


int i, v[5],*a;

a=0;
for (i=0; i<5; i++)
{
v[i]=i;
printf ("%d %d %d %d\n",((v-a)<<(sizeof(int)>>1))+i+3,((v-a)<<(sizeof(int)>>1))+i+2,((v-a)<<(sizeof(int)>>1))+i+1,((v-a)<<(sizeof(int)>>1))+i);
}


Si basa sul concetto che una differenza di puntatori e' equivalente al numero di elementi puntati dal puntatore

Ciao :)
Dunque....premettendo che vengo da due corsi di Fondamenti di Informatica (I e II...il primo, veramente RIDICOLO, solo sul C e il secondo su C e C++) le mie conoscenze non mi consentono di comprendere quello che hai scritto :)

Saresti così gentile da spiegarmi la tua soluzione (ovviamente non c'è fretta, quando avrai tempo...:))?

Non sapevo che la differenza tra puntatori restituisse il numero di elementi puntati da quello posto a sinistra dell'operatore -.

Inoltre, non conosco il significato di quelle parentesi angolari in C :(
Mi riferisco a << e >>

Grazie anticipatamente :)

fek
24-07-2005, 11:23
a) Non viene definito in standard l'ordine di valutazione.

Appunto. Da qui l'errore.

d) Ora mi dici che il mio esempio era errato perche' lo standard non definisce l'ordine di valutazione dei parametri.

Non lo dico ora, l'ho detto dal primo post.

1) Lo standard del passaggio dei paramentri sullo stack e' cdecl.

No. Non lo e'. Ti ho postato anche tutto lo Standard del C. Trovami il paragrafo dove lo Standard impone il passaggio cdecl.

3) Da cui: l'esempio che ho mostrato una volta compilato funziona.

Il fatto che "funzioni" su un compilatore, non vuol dire nulla. E' codice indefinito, e come tale Standard alla mano puo' smettere di funzionare con un altro compilatore, oppure con una versione successiva dello stesso compilatore, oppure compilando con opzioni differenti. Il codice che hai scritto e' errato. Fattene una ragione e se hai rimostranze puoi sempre scrivere al comitato di standardizzazione e dirgli che hanno sbagliato.

In caso ti fosse sfuggito:

[#10] The order of evaluation of the function designator,
the actual arguments, and subexpressions within the actual
arguments is unspecified, but there is a sequence point
before the actual call.

[#12] EXAMPLE In the function call

(*pf[f1()]) (f2(), f3() + f4())

the functions f1, f2, f3, and f4 may be called in any order.
All side effects have to be completed before the function
pointed to by pf[f1()] is called.

http://www.open-std.org/jtc1/sc22/open/n2794/n2794.txt

4) Per sostenere la non funzionalita' verrei vedere un esempio di codice che in C venga valutato da sinistra a destra "SENZA" forzatura pascal.

(*pf[f1()]) (f2(), f3() + f4())

the functions f1, f2, f3, and f4 may be called in any order.

Un codice qualunque compilato con le opzioni opportune puo' essere valutato in qualunque ordine.

Non vedo perche' insistere, non c'e' nulla di male nello sbagliare. Hai fatto un errore, non succede nulla, tutti li commettiamo. Ora Swarzy sa' qualcosa in piu'.

Oppure vuoi solo avere l'ultima parola, in quel caso scrivi "Voglio l'ultima parola" e la finiamo qui, ma non scrivere cose palesemente inesatte per cercare di aver ragione ( (C) 2005 Paolo Corsini )

repne scasb
24-07-2005, 11:24
Ciao :)
Non sapevo che la differenza tra puntatori restituisse il numero di elementi puntati da quello posto a sinistra dell'operatore -.

In effetti e' poco noto, ma e' possibile fare una differenza di puntatori se entrambi i puntatori puntano al medesimo tipo di dato. Ossia: supponendo che '*a' sia un puntatore int e '*b' sia un puntatore sempre ad int 'a-b' restituisce il "numero di "int" tra a e b'. Se '*b' fosse stato un puntatore a "float" (per esempio) la differenza sarebbe stata o con poco senso o sospetta. Ho quindi inizializzato un puntatore ad int chiamato '*a', l'ho settato a zero, ed ho quindi fatto la differenza tra v ed a (v rappresenta la locazione di memeria da cui inizia l'array v[]). Questa differenza rappresenta quindi il numero di 'int' tra 0 e v; per ottenere di nuovo l'indirizzo di v e' necessario moltiplicare tale valore per il numero di byte di cui e' composto un int (in un compilatore a 32 bit di solito sono 4). Quindi dove leggi '",((v-a)<<(sizeof(int)>>1))+i+3', leggi pure (v-a)*4+i+3 (ne caso che un int sia composto da 4 byte).


Inoltre, non conosco il significato di quelle parentesi angolari in C :(
Mi riferisco a << e >>

Indicano uno shift a destra o sinistra di uno o piu' bit. E' utile quando si deve moltiplicare o dividere per un multiplo di due. Per esempio se devo moltiplicare a*8 posso scrivere 'a<<3'; tutto cio' perche per una CPU generica in generale uno shift e' piu' semplice di una moltiplicazione; sizeof l'ho utilizzato per sapere quanto e' grosso un 'int' sul tuo compilatore non sapendo se stai utilzzando un compilatore a 16/32/64 bit.

E' in definitiva una soluzione un po 'esotica" ma funziona (credo che sia diversa da quella che ha supposto il tuo professore).

fek
24-07-2005, 12:01
Ecco l'esempio che volevi:

http://www.embedded.com/shared/printableArticle.jhtml?articleID=9900607


Left to right?

Function f below simply writes the values of its parameters to the standard output stream:


#include <stdio.h>
void f(int i, int j)
{
printf("i = %d; j = %d\n", i, j);
}

Now, suppose you call the function using:



int n;
...
n = 0;
f(n++, n);

[...]

I tried this with four different compilers on my Pentium-based PC:

* Borland C++ 5.5 for Windows
* Metrowerks CodeWarrior Pro 6.0 for Windows
* Microsoft Visual C++ 6.0 for Windows
* GNU gcc 3.0.3 running under Cygwin

Not one compiles code that produces the "obvious" result. Rather, they all compile code that yields:

i = 0; j = 0

I also compiled the code using two different compilers for the ARM7 processor:

* ARM Development System trial version 1.1 (a version of Metrowerks CodeWarrior)
* GNU gcc 3.0.3

Both of these compilers compile code that produces the "obvious" output:

i = 0; j = 1

Are the Pentium compilers wrong? No, they're simply exercising the freedom granted by the Standard. According to the Standard, the order of evaluation for the arguments in a function call is unspecified. Thus, a compiler is free to interpret:

n = 0;
f(n++, n);

in a few different ways:

1. It can evaluate the arguments from left to right, and perform the post-increment on the left argument before evaluating the right argument. This yields the "obvious" result:

i = 0; j = 1

2. It can evaluate the arguments from left to right, and delay the post-increment on the left argument until after evaluating the right argument. In that case, both arguments will be zero:

i = 0; j = 0

3. It can evaluate the arguments from right to left. As in the second, the post-increment doesn't get done until after both arguments are evaluated. Both arguments will be zero:

i = 0; j = 0


Stesso codice. Risultati diversi su compilatori diversi che valutano in ordine diverso.

E continua:


A function call has evaluated the argument once it has copied n into the parameter storage area for the call (on the stack or in a register).

Ovvero puo' decidere indifferentemente se passare gli argomenti valutati in registri o usando lo stack.

E poi:

Always one way or the other?

Since the order of evaluation for function arguments is unspecified, a compiler can evaluate the arguments to a call in any order, as long as it evaluates all the arguments before jumping to the function. In theory, a compiler could use even a random number generator to determine the order of evaluation for each call. In practice, most compilers seem to use either left-to-right or right-to-left for all calls. The four Pentium compilers I tested evaluate function arguments from right to left.

I was surprised to find that the two compilers for the ARM7 varied the order of evaluation from call to call. As I mentioned earlier, for:

Stesso compilatore, varia l'ordine di valutazione anche all'interno dello stesso programma e senza direttive, in base ad una qualche euristica propria.

Conclusione:


All other things being equal, portable code is better than non-portable code. Function calls that depend on the order of argument evaluation are non-portable, and you should avoid them.

How do you know if you've written a call with an evaluation order dependency? Static analyzers such as lint can find them for you. (This month's "Beginner's Corner," on p. 55, features a general description of lint.) When I ran each of the function calls above through Gimpel Software's PC-Lint, it produced the following message:

Warning 564: variable 'n' depends on order of evaluation

Direi che e' conclusivo.
Questo e' il mio ultimo post sull'argomento.

swarzy85
24-07-2005, 12:26
Non vedo perche' insistere, non c'e' nulla di male nello sbagliare. Hai fatto un errore, non succede nulla, tutti li commettiamo. Ora Swarzy sa' qualcosa in piu'.
Eh beh, giusto un pò....:)

71104
24-07-2005, 13:05
Quale sarebbe questo tipo "specifico" di compilatori C? quelli che valutano i parametri nello stesso ordine in cui li spingono nello stack.

swarzy85
24-07-2005, 13:33
In effetti e' poco noto, ma e' possibile fare una differenza di puntatori se entrambi i puntatori puntano al medesimo tipo di dato. Ossia: supponendo che '*a' sia un puntatore int e '*b' sia un puntatore sempre ad int 'a-b' restituisce il "numero di "int" tra a e b'. Se '*b' fosse stato un puntatore a "float" (per esempio) la differenza sarebbe stata o con poco senso o sospetta. Ho quindi inizializzato un puntatore ad int chiamato '*a', l'ho settato a zero, ed ho quindi fatto la differenza tra v ed a (v rappresenta la locazione di memeria da cui inizia l'array v[]). Questa differenza rappresenta quindi il numero di 'int' tra 0 e v;
Si si, questo sono riuscito a capirlo, ti ringrazio :)

per ottenere di nuovo l'indirizzo di v e' necessario moltiplicare tale valore per il numero di byte di cui e' composto un int (in un compilatore a 32 bit di solito sono 4).
Ecco, qui non ho capito perchè.
Se moltiplico il numero di elementi che ci sono tra v ed a (con a inizializzato a 0 e quindi considero solo il numero di elementi di v) per il numero di byte di un interno (visto che v è un vettore di interi), non ottengo semplicemente la quantità di memoria allocata per quel vettore?
Come mai mi restituisce proprio l'indirizzo del vettore? (quindi quello del primo byte)

Quindi dove leggi '",((v-a)<<(sizeof(int)>>1))+i+3', leggi pure (v-a)*4+i+3 (ne caso che un int sia composto da 4 byte).
Dunque, penso di sbagliare ma ti pongo ugualmente la domanda :)
Analizzo la parte di codice che ho quotato e ti dico passo passo cosa ho capito:

(v-a) -> numero di elementi del vettore v

(v-a)<<(sizeof(int)>>1) -> moltiplicazione del numero di elementi di v per la dimensione di un intero fratto 2. Nel mio caso, vengono allocati 4 byte per un intero, per cui (sizeof(int)>>1) non dovrebbe restituire 4 shiftato a destra di 1 (e quindi diviso per 2^1 ?)
In definitiva, fino a questo punto, secondo quello che ho capito, si ha: (v-a) * 2
Ovviamente la conclusione alla quale sono pervenuto è sicuramente errata altrimenti le tue righe di codice mi restituirebbero risultati ben diversi da quelli che ho ottenuto :)
In cosa sto sbagliando?

(v-a)<<(sizeof(int)>>1))+i+3 Qui credo ci sia un errore. Dunque, la prima parte (v-a)<<(sizeof(int)>>1)) resta costante e non varia mai. In pratica lavoro sempre in relazione all'indirizzo del vettore, quindi al primo byte allocato per il vettore.
A questo inizialmente aggiungo solo i (che nel primo ciclo ha valore 0) e quindi mi ritrovo perfettamente. Nel secondo ciclo aggiungo i+1 e quindi ottengo l'indirizzo incrementato di 1 e così via, fino ad i+3.
Fino a qui sono perfettamente d'accordo.

Quando però i viene incrementato di 1 e quindi passo a v[1], dovrò aumentare l'indirizzo di v di 4 per ottenere il primo byte allocato per v[1], no?
Invece, secondo quella sintassi, aggiungo soltanto 1 e mi ritrovo con il secondo byte allocato per v[0].
Spero di essermi espresso in maniera abbastanza chiara (anche se ho i miei dubbi).

Per cercare una conferma ho compilato il tuo codice e ho ottenuto questo risultato:
v[0] che si trova ai byte numero 4398467 4398466 4398465 4398464 vale = 0
v[1] che si trova ai byte numero 4398468 4398467 4398466 4398465 vale = 1
v[2] che si trova ai byte numero 4398469 4398468 4398467 4398466 vale = 2
v[3] che si trova ai byte numero 4398470 4398469 4398468 4398467 vale = 3
L'ultimo byte della seconda riga doveva essre 4398468 e non 4398466.
Altrimenti v[0] e v[1] verrebbero scritti sulla stessa area di memoria.

Vabbè, la seconda parte penso si possa correggere molto facilmente. Non riesco a capire, però, perchè (v-a)<<(sizeof(int)>>1)) punta al primo byte allocato per v.
Stando a quello che mi hai detto, dovremmo avere (v-a)*4; però, a me non tornano i conti perchè ottengo (v-a)*2.
In cosa sbaglio?

Ti ringrazio anticipatamente per la disponibilità e chiedo scusa per le domande che vi possono sembrare banali.

P.S. Francesco grazie anche a te per quei documenti. Entrando in questa sezione ho capito che di C e C++ non so proprio niente....

repne scasb
24-07-2005, 13:55
Ecco, qui non ho capito perchè.
Se moltiplico il numero di elementi che ci sono tra v ed a (con a inizializzato a 0 e quindi considero solo il numero di elementi di v) per il numero di byte di un interno (visto che v è un vettore di interi), non ottengo semplicemente la quantità di memoria allocata per quel vettore?
Come mai mi restituisce proprio l'indirizzo del vettore? (quindi quello del primo byte)

v sia allocato alla locazione di memoria 101372.
a sial allocato alla locazione di memoria 0.
Ora (v-a) restituisce il numero di 'int' tra 101372 e 0, ossia 25343 (un int=4 byte). Da cui (v-a)*4=101372 che e' proprio l'indirizzo di partenza di v.

(v-a) -> numero di elementi del vettore v

Esatto.

(v-a)<<(sizeof(int)>>1) -> moltiplicazione del numero di elementi di v per la dimensione di un intero fratto 2. Nel mio caso, vengono allocati 4 byte per un intero, per cui (sizeof(int)>>1) non dovrebbe restituire 4 shiftato a destra di 1 (e quindi diviso per 2^1 ?)
In definitiva, fino a questo punto, secondo quello che ho capito, si ha: (v-a) * 2

No. sizeof(int)=4, 4>>1=2, (v-a)<<2=(v-a)*4. Ossia
<<1=*2, >>1=/2
<<2=*4, >>2=/4
<<3=*8, >>3=/8
...
...
<<n=2^n, >>n=/2^n

(v-a)<<(sizeof(int)>>1))+i+3 Qui credo ci sia un errore.

Adesso ho capito cosa volevi ottenere. Prima non lo avevo ben chiaro. Devi semplicemente incrementare i di 4 nel ciclo for (un int=4 byte), per la precisione devi incrementarlo di sizeof(int).

71104
24-07-2005, 14:02
(v-a)<<(sizeof(int)>>1))+i+3 Qui credo ci sia un errore. infatti hai chiuso una parentesi di troppo :p

repne scasb
24-07-2005, 14:15
Cosi' e' piu' rigoroso.


#include <stdio.h>

void main(void)

{
int i,j,v[5],*a;

a=0;
for (i=0;i<5;i++)
{
v[i]=i;
printf("v[%d] che si trova ai byte numero",i);
for(j=0;j<sizeof(int);j++)
printf (" %u",(&v[i]-a)*sizeof(int)+j);
printf(" vale = %d\n",v[i]);
}
}

swarzy85
24-07-2005, 14:21
v sia allocato alla locazione di memoria 101372.
a sial allocato alla locazione di memoria 0.
Ora (v-a) restituisce il numero di 'int' tra 101372 e 0, ossia 25343 (un int=4 byte). Da cui (v-a)*4=101372 che e' proprio l'indirizzo di partenza di v.
Quindi più che gli elementi del vettore v, (v-a) rappresenta tutti gli interi che possono essere allocati tra la locazione di memoria di a e quella di v.
Giusto?


No. sizeof(int)=4, 4>>1=2, (v-a)<<2=(v-a)*4. Ossia
<<1=*2, >>1=/2
<<2=*4, >>2=/4
<<3=*8, >>3=/8
...
...
<<n=2^n, >>n=/2^n
esatto, hai perfettamente ragione; ho dimenticato di moltiplicare per 2^2 e moltiplicavo solo per 2 dimenticando che devo riferirmi alle potenze di 2 :)

Adesso ho capito cosa volevi ottenere. Prima non lo avevo ben chiaro. Devi semplicemente incrementare i di 4 nel ciclo for (un int=4 byte), per la precisione devi incrementarlo di sizeof(int).
Esatto, ti ringrazio, molto chiara :)

repne scasb
24-07-2005, 14:21
infatti hai chiuso una parentesi di troppo :p

Questo era il mio codice originario:


((v-a)<<(sizeof(int)>>1))+i+3


Comunque, se queste "devono" essere le scocciature o le discussioni "sulla natura del sesso degli angeli", che mi devo sorbire per aiutare un utente che chiede consigli/aiuti, sono sicura che per il futuro mi asterro'.

swarzy85
24-07-2005, 14:22
infatti hai chiuso una parentesi di troppo :p
No, non è quello il problema; è solo un errore di trascrizione ma mi riferivo ad altro :)

swarzy85
24-07-2005, 14:23
Questo era il mio codice originario:


((v-a)<<(sizeof(int)>>1))+i+3


Comunque, se queste "devono" essere le scocciature o le discussioni "sulla natura del sesso degli angeli", che mi devo sorbire per aiutare un utente che chiede consigli/aiuti, sono sicura che per il futuro mi asterro'.
Tranquilla, ho sbagliato io a ricopiare, non è stata una tua mancanza :)
Ti ringrazio per l'aiuto :)

repne scasb
24-07-2005, 14:25
Quindi più che gli elementi del vettore v, (v-a) rappresenta tutti gli interi che possono essere allocati tra la locazione di memoria di a e quella di v.
Giusto?

Si.

C'e' solo un'obiezione al ragionamento (dovresti essere in grado di notarla), che il tuo professore potrebbe farti se gli presenti un tale codice.

swarzy85
24-07-2005, 14:28
Si.

C'e' solo un'obiezione al ragionamento (dovresti essere in grado di notarla), che il tuo professore potrebbe farti se gli presenti un tale codice.
Ti riferisci al fatto che, in realtà, in ogni stampa faccio riferimento all'indirizzo del byte allocato per il primo elemento e non, di volta in volta, al primo byte allocato per ogni elemento del vettore?

repne scasb
24-07-2005, 14:35
Ti riferisci al fatto che, in realtà, in ogni stampa faccio riferimento all'indirizzo del byte allocato per il primo elemento e non, di volta in volta, al primo byte allocato per ogni elemento del vettore?

No.

71104
24-07-2005, 16:42
Comunque, se queste "devono" essere le scocciature o le discussioni "sulla natura del sesso degli angeli", che mi devo sorbire per aiutare un utente che chiede consigli/aiuti, sono sicura che per il futuro mi asterro'. ehm... -___-' :doh:
ma non sarai un tantino schizzinosa? (nuuu...) :rolleyes:
quel messaggio l'avresti potuto tranquillamente ignorare, era chiaramente una sciocchezza che ho scritto per incrementare il post counter :D
piuttosto, se sei tanto assetata di... messaggi seri!! :D perché non vai allora a leggere quello che avevo scritto subito prima della cavolata? ;)

maxithron
24-07-2005, 18:00
Il vostro "fraintendersi" reciproco è nato non ho capito ancora per quale ragione, dato che in "prima pagina" eravate praticamente in linea:

originariamente inviato da Fek
Lo Standard C++ non da' garanzie sull'ordine di valutazione degli argomenti di una chiamata a funzione. Questo codice e' "Undefined" in C++.

Non ricordo a memoria se lo Standard del C da' garanzia sull'ordine di valutazione (mi sembrerebbe molto strano se lo facesse).


originariamente inviato da repne scasb
Il passaggio dei parametri puo' avvenire da destra verso sinistra da sinistra verso destra, con allineamento dello stack a carico del chiamante o del chiamato, per registro, o in altri modi piu' o meno esotici.

I due metodi piu' utilizzati sono da destra a sinistra con stack a carico del chiamante, e da sinistra a destra con stack a carico del chiamato. Il secondo metodo si chiama "passaggio di paramentri con convenzione pascal", il primo "standard C". Ci sarebbe da verificare se il primo metodo chiamato "standard C" e' in effetti uno standard del C.


Le due frasi in grassetto credo che rispecchino che fino a quel punto avevate entrambi qualche dubbio, che condividevate anche :) In seguito invece, vi siete un pò pizzicati ;)

cionci
24-07-2005, 19:57
quel messaggio l'avresti potuto tranquillamente ignorare, era chiaramente una sciocchezza che ho scritto per incrementare il post counter :D
Che quindi potevi anche evitare...

71104
24-07-2005, 20:30
Che quindi potevi anche evitare... eddai cionci!! un forum non può dirsi degno di questo nome se manca di spam!!! :D
hai mai visto un forum serio privo di spam??? :D
purché non ci si faccia l'abitudine, su questo sono d'accordo! :rolleyes:

fantoibed
01-09-2005, 23:02
Comunque, se queste "devono" essere le scocciature o le discussioni "sulla natura del sesso degli angeli", che mi devo sorbire per aiutare un utente che chiede consigli/aiuti, sono sicura che per il futuro mi asterro'.Spero di cuore che tu non ti astenga. E' veramente un piacere leggerti. :p