Discussione:
Esercizio su precedenza operatori
(troppo vecchio per rispondere)
Luca
2016-04-21 11:00:33 UTC
Permalink
Ciao,

mi sembra ci siano un errore su questo esercizio:
Loading Image...

Al punto 2 avrei scritto:
a= b+= (c++) -d + --e / (-f)

"decremento prefisso" e "-unario" hanno la stessa precenza ma vanno
valutati da destra verso sinistra, giusto?
Poi magari il risultato è uguale, ma a livello concettuale, di regole,
vedo un errore.

Grazie

---
Questa e-mail è stata controllata per individuare virus con Avast antivirus.
https://www.avast.com/antivirus
f***@gmail.com
2016-04-21 11:10:33 UTC
Permalink
Post by Luca
Ciao,
http://i64.tinypic.com/25qf12x.jpg
a= b+= (c++) -d + --e / (-f)
"decremento prefisso" e "-unario" hanno la stessa precenza ma vanno
valutati da destra verso sinistra, giusto?
Boh, no, perché? Non ci sono sequence point in mezzo, e anche il diviso va da
sinistra a destra. O avevi in mente altro?
Post by Luca
Poi magari il risultato è uguale, ma a livello concettuale, di regole,
vedo un errore.
Sì, è esattamente uguale. Per quel che vale, anch'io ragiono come scritto
sulla jpeg.

Ciao!
Luca
2016-04-21 13:39:38 UTC
Permalink
Post by f***@gmail.com
Sì, è esattamente uguale. Per quel che vale, anch'io ragiono come scritto
sulla jpeg.
allora mi sa che non ho capito come funziona.

Se ho:

int a,b=2,c=3;
a= --b / -c;

"--" e "-" hanno la stessa piorità e vanno valutati da destra verso
sinistra, quindi si esegue prima -c:
c=2

poi --b:
b=1

e infine b/c ("/" ha priorità inferiore rispetto a "--" e "-")
a=2/1=1

Cosa non ho capito? :)
Grazie

---
Questa e-mail è stata controllata per individuare virus con Avast antivirus.
https://www.avast.com/antivirus
f***@gmail.com
2016-04-21 15:19:27 UTC
Permalink
Post by Luca
Post by f***@gmail.com
Sì, è esattamente uguale. Per quel che vale, anch'io ragiono come scritto
sulla jpeg.
allora mi sa che non ho capito come funziona.
int a,b=2,c=3;
a= --b / -c;
"--" e "-" hanno la stessa piorità e vanno valutati da destra verso
c=2
b=1
e infine b/c ("/" ha priorità inferiore rispetto a "--" e "-")
a=2/1=1
Cosa non ho capito? :)
Devi ricordarti che entra in azione un altro concetto importante..

Matematicamente, se esegui prima --b o -c è la stessa identica cosa.

Tu mi potresti dire, sì, ma è teoricamente importante se scrivo qualcosa come
a = --b / -b
Al che ti risponderei: quella sopra è UB (undefined behavior). Lo è perché
modifichi e usi allo stesso tempo una variabile senza un sequence point in
mezzo.

Quindi, per quanto ti riguarda come programmatore c, se è matematicamente
equivalente e tutti i side effects sono separati da sequence points non te
ne devi preoccupare (anche perché dopo il parser, l'ottimizzatore e il
compilatore chissà l'espressione cosa diventa a livello macchina! :) ).

Ciao!
Jack
2016-04-21 12:38:39 UTC
Permalink
Post by Luca
Ciao,
http://i64.tinypic.com/25qf12x.jpg
a= b+= (c++) -d + --e / (-f)
Il punto critico e' c++. c viene prima usato, e poi incrementato.
Quindi le parentesi non vanno messe attorno a c++, ma e' come scrivere:
a= b+= c - d + (--e) / (-f);
c++;

Ciao Jack
Andrea Rimicci
2016-04-21 13:44:06 UTC
Permalink
Post by Luca
a= b+= (c++) -d + --e / (-f)
"decremento prefisso" e "-unario" hanno la stessa precenza ma vanno
valutati da destra verso sinistra, giusto?
Sbagliato. L'ordine di valutazione degli operatori in somme e
sottrazioni e' da sx verso dx, che e' differente da "prima gli unari
ovunque siano in una somma o sottrazione poi gli altri" che invece
vorresti fare tu.

Saro' ancora piu' dettagliato della tua immagine jpg, per farti vedere
la differenza, scomponendo l'albero delle precedenze e segnando
l'ordine di valutazione (1)..(n):


a = b+= c++ - d + --e / -f
a = ( b+= c++ - d + --e / -f )
a = ( b+= ( c++ - d + --e / -f ) )
a = ( b+= ( (c++) - d + --e / -f ) )
a = ( b+= ( (c++) - d + ( --e / -f ) ) )
a = ( b+= ( (c++) - d + ( ( --e ) / -f ) ) )
a = ( b+= ( (c++) - d + ( ( --e ) / ( -f ) ) ) )
----- --- ------- ------
(1) (2) (4) (5)
--------- -------------
(3) (6)
--------------------
(7)
-------------------------------------------
(8)
------------------------------------------------
(9)


Se sopra vedi solo scarabocchi, prova a usare un font monospaced.

Per il "c++" le parentesi vanno bene, perche' il valore di "c++" e'
sempre "c", mentre l'incremento e' un "side-effect" che ha effetto al
successivo uso di "c".

Semanticamente, si e' vero che il risultato finale e' lo stesso, MA se
il contesto sono operazioni valide. In caso di eccezioni (div. per
zero, overflow, altro) la valutazione si "ferma" all'eccezione senza
valutare il resto, per esempio se "(c++) - d" causasse un
under/overflow, seguendo l'ordine di valutazione che ho descritto, la
variable "e" rimarrebbe intoccata, e invece cambierebbe se "--e"
venisse valutato prima (di "(c++) - d"), cosa che invece non deve
accadere.

Sono piccole disquisizioni, ma alla base di tanti "exploit", mi fa
piacere che ogni tanto se ne parla ;)
--
andrea - ri mi cci, name
LutherBlissett
2016-04-21 14:45:10 UTC
Permalink
On 21/04/2016 15:44, Andrea Rimicci wrote:
[...]
Post by Andrea Rimicci
Sono piccole disquisizioni, ma alla base di tanti "exploit", mi fa
piacere che ogni tanto se ne parla ;)
Interessante, ma io ho rinunciato a ricordarmele: vado di parentesi. 8-D
Jack
2016-04-22 07:20:52 UTC
Permalink
Post by Andrea Rimicci
a = ( b+= ( (c++) - d + --e / -f ) )
Per il "c++" le parentesi vanno bene, perche' il valore di "c++" e'
sempre "c", mentre l'incremento e' un "side-effect" che ha effetto al
successivo uso di "c".
eh no.
se metti le parentesi il compilatore di calcola prima c++, e poi fa la sottrazione.
Scrivere (c++) e' equivalente a scrivere ++c.

Ciao Jack
Andrea Rimicci
2016-04-26 08:50:24 UTC
Permalink
Post by Jack
Scrivere (c++) e' equivalente a scrivere ++c.
Le parentesi "forzano" un'ordine di precedenza, ma non modificano
affatto la semantica degli operatori.

Prova questo:

int main (void){
int a=10;
float b;
b=(a++)/2.;
printf("%f",b);
return 0;
}
--
andrea - ri mi cci, name
Jack
2016-04-26 11:41:08 UTC
Permalink
Post by Andrea Rimicci
Post by Jack
Scrivere (c++) e' equivalente a scrivere ++c.
Le parentesi "forzano" un'ordine di precedenza, ma non modificano
affatto la semantica degli operatori.
b=(a++)/2.;
qui quello che si vuole fare (con le parentesi, le metti apposta) e': prendi a, aggiungi 1 e poi dividi per 2.
Quello che viene fatto e' prendi a, dividi per 2 e poi alla fine aggiungi 1.

Visto che il risultato e' 5 le parentesi in questo caso non vengono cagate.
Quindi o e' un grave errore, oppure (e a questo punto propendo per questa possibilita') non ho capito quando viene applicato il post incremento.

perche':
y = x++ * 2;
y = ++x * 2;

e' chiaro.

ma:
y = (x++) * 2;
mi aspetto si comporti come y = ++x * 2 visto che ho messo una parentesi apposta per far calcolare x++ _prima_ di fare la moltiplicazione.

Boh

Ciao Jack
enoquick
2016-04-26 12:47:26 UTC
Permalink
Post by Jack
Post by Andrea Rimicci
Post by Jack
Scrivere (c++) e' equivalente a scrivere ++c.
Le parentesi "forzano" un'ordine di precedenza, ma non modificano
affatto la semantica degli operatori.
b=(a++)/2.;
qui quello che si vuole fare (con le parentesi, le metti apposta) e': prendi a, aggiungi 1 e poi dividi per 2.
Quello che viene fatto e' prendi a, dividi per 2 e poi alla fine aggiungi 1..
Visto che il risultato e' 5 le parentesi in questo caso non vengono cagate.
Quindi o e' un grave errore, oppure (e a questo punto propendo per questa possibilita') non ho capito quando viene applicato il post incremento.
y = x++ * 2;
y = ++x * 2;
e' chiaro.
y = (x++) * 2;
mi aspetto si comporti come y = ++x * 2 visto che ho messo una parentesi apposta per far calcolare x++ _prima_ di fare la moltiplicazione.
Boh
Ciao Jack
Non e' cosi,le parentesi forzano l'ordine di precedenza come e' stato
scritto.

L'espressione (x++) * 2 funziona cosi:

Viene valutato (x++) che risulta x

poi il risultato (che e' x) viene moltiplicato * 2

viene posto il risultato in y e incrementato x
Jack
2016-04-26 14:11:57 UTC
Permalink
Post by enoquick
Non e' cosi,le parentesi forzano l'ordine di precedenza come e' stato
scritto.
Viene valutato (x++) che risulta x
poi il risultato (che e' x) viene moltiplicato * 2
viene posto il risultato in y e incrementato x
ok, ci sono arrivato.
in pratica e' come avere (x++ + 0) * 2, che quindi diventa (x + 0) * 2 => x * 2 (con x uguale al valore iniziale).

Bello contorto. Continuero' ad evitare di mettere i pre/post incrementi nelle equazioni :P

Ciao Jack
enoquick
2016-04-26 20:19:20 UTC
Permalink
Post by Jack
Post by enoquick
Non e' cosi,le parentesi forzano l'ordine di precedenza come e' stato
scritto.
Viene valutato (x++) che risulta x
poi il risultato (che e' x) viene moltiplicato * 2
viene posto il risultato in y e incrementato x
ok, ci sono arrivato.
in pratica e' come avere (x++ + 0) * 2, che quindi diventa (x + 0) * 2 => x * 2 (con x uguale al valore iniziale).
Esatto
Post by Jack
Bello contorto. Continuero' ad evitare di mettere i pre/post incrementi nelle equazioni :P
Ciao Jack
Non e' difficile,basta fare un po di pratica.
Pero' espressioni complesse e contorte e' meglio spezzarle ed usare le
parentesi,almeno per la leggibilita di chi deve manutenere il codice in
futuro; e puo essere anche lo stesso individuo fisico a mesi o anni di
distanza.
Per di piu i compilatori di oggi sono molto capaci ad ottimizzare il
codice tanto che differenze tra i due modi di scrivere non ce ne sono (o
sono irrilevanti) a livello di codice macchina generato ed ottimizzato.
4ndre4
2016-09-18 17:39:57 UTC
Permalink
On 26/04/2016 15:11, Jack wrote:

[...]
Post by Jack
in pratica e' come avere (x++ + 0) * 2, che quindi diventa (x + 0) * 2 => x * 2 (con x uguale al valore iniziale).
Non esattamente. Quel che bisogna tenere a mente e` che l'incremento
viene demandato al prossimo sequence point e le parentesi non servono ad
anticipare quell'operazione.
--
4ndre4
Andrea Rimicci
2016-04-26 14:48:23 UTC
Permalink
Post by Jack
non ho capito quando viene applicato il post incremento.
Viene applicato subito ma la sua semantica e' il valore precedente
l'incremento.

Per dirla in termini meno informatici ma spero piu' capibili in
generale, a++ significa: il valore di "a" in quel momento e in
quell'espressione, ma se l'ordine di valutazione dell'espressione
trova "a" da qualche altra parte DOPO, allora il valore di "a" e'
quello incrementato.

Esercizi:

int a=0;
(a-- == a) e' sempre vero o sempre falso?
(--a == a++) ?
(a++ == a--) ?
(a == a--) ?

;)
--
andrea - ri mi cci, name
4ndre4
2016-09-18 11:42:32 UTC
Permalink
On 21/04/2016 14:44, Andrea Rimicci wrote:

[...]
Post by Andrea Rimicci
a = b+= c++ - d + --e / -f
[...]
Post by Andrea Rimicci
a = ( b+= ( (c++) - d + ( ( --e ) / ( -f ) ) ) )
[...]
Post by Andrea Rimicci
In caso di eccezioni (div. per
zero, overflow, altro) la valutazione si "ferma" all'eccezione senza
valutare il resto, per esempio se "(c++) - d" causasse un
under/overflow, seguendo l'ordine di valutazione che ho descritto, la
variable "e" rimarrebbe intoccata, e invece cambierebbe se "--e"
venisse valutato prima (di "(c++) - d"), cosa che invece non deve
accadere.
Non ricordo precisamente cosa dica lo standard in proposito, ma non
credo che l'ordine di valutazione dell'espressione sia necessariamente
quello che hai descritto con le parentesi. Se l'ordine di valutazione di
--e non influenza il risultato, il compilatore e` libero di piazzare
quell'esecuzione in qualunque ordine. In sostanza, non e` affatto detto
che --e sia eseguito prima o dopo di c++. Viene, pero`, sicuramente
eseguito prima della divisione per f.
--
4ndre4
"The use of COBOL cripples the mind; its teaching should, therefore, be
regarded as a criminal offense." (E. Dijkstra)
"Ora, questo "Delta11" non è nulla di più di uno scemo del villaggio" -
(L'Accalappiafasci)
Giacomo Degli Esposti
2016-09-19 09:57:29 UTC
Permalink
Post by 4ndre4
[...]
Post by Andrea Rimicci
a = b+= c++ - d + --e / -f
[...]
Post by Andrea Rimicci
a = ( b+= ( (c++) - d + ( ( --e ) / ( -f ) ) ) )
[...]
Post by Andrea Rimicci
In caso di eccezioni (div. per
zero, overflow, altro) la valutazione si "ferma" all'eccezione senza
valutare il resto, per esempio se "(c++) - d" causasse un
under/overflow, seguendo l'ordine di valutazione che ho descritto, la
variable "e" rimarrebbe intoccata, e invece cambierebbe se "--e"
venisse valutato prima (di "(c++) - d"), cosa che invece non deve
accadere.
Non ricordo precisamente cosa dica lo standard in proposito, ma non
credo che l'ordine di valutazione dell'espressione sia necessariamente
quello che hai descritto con le parentesi. Se l'ordine di valutazione di
--e non influenza il risultato, il compilatore e` libero di piazzare
quell'esecuzione in qualunque ordine. In sostanza, non e` affatto detto
che --e sia eseguito prima o dopo di c++. Viene, pero`, sicuramente
eseguito prima della divisione per f.
Esatto.
Lo standard elenca esplicitamente i casi di sequence point
(IIRC: operatore '&&', operatore ',', chiamata di funzione, ';')
e dice che tutto il resto e' valutabile nell'ordine che il
compilatore preferisce (a patto di mantenere la correttezza).

In quella espressione c'e' un solo sequence point quindi non c'e'
alcuna garanzia sulla sequenza di valutazione.

ciao
Giacomo
Andrea Rimicci
2016-09-19 11:02:56 UTC
Permalink
Post by 4ndre4
Non ricordo precisamente cosa dica lo standard in proposito, ma non
credo che l'ordine di valutazione dell'espressione sia necessariamente
quello che hai descritto con le parentesi. Se l'ordine di valutazione di
--e non influenza il risultato, il compilatore e` libero di piazzare
quell'esecuzione in qualunque ordine. In sostanza, non e` affatto detto
che --e sia eseguito prima o dopo di c++. Viene, pero`, sicuramente
eseguito prima della divisione per f.
Ciao, si è esatto, lo standard lascia il compilatore libero di fare
quello che vuole nell'ordine di valutazione delle espressioni sulle
quali un operatore viene applicato.

Nell'esempio che ho fatto, poi liberamente permutare 1 con 2, 4 con 5
e 3 con 6 (come ordine di valutazione).

E' il motivo per cui ho dovuto dire che stavo seguendo un ordine
preciso di esecuzione, prima di dire cosa può o non può succedere.

Per questo motivo, se usi espressioni con "side-effects" (es. classico
il ++), è consigliabile evitare di usare la stessa variabile coinvolta
in più parti dell'espressione.

Per completezza, una volta si poteva dire che l'ordine effettivamente
seguito dipende dal compilatore, ma adesso non più, perché con
l'esecuzione su più thread di una espressione complessa, potrebbe
accadere che una espressione venga valutata prima o dopo un'altra,
senza poterlo predire, in momenti diversi e con lo stesso compilatore.
--
andrea - ri mi cci, name
4ndre4
2016-09-19 12:29:36 UTC
Permalink
On Monday, 19 September 2016 12:02:57 UTC+1, Andrea Rimicci wrote:

[...]
Post by Andrea Rimicci
Per questo motivo, se usi espressioni con "side-effects" (es. classico
il ++), è consigliabile evitare di usare la stessa variabile coinvolta
in più parti dell'espressione.
Piu` che sconsigliabile, potrebbe portare ad un undefined behaviour - a seconda dell'espressione.
Post by Andrea Rimicci
Per completezza, una volta si poteva dire che l'ordine effettivamente
seguito dipende dal compilatore, ma adesso non più
I thread non c'entrano nulla. Se piu` thread eseguissero pezzi di un'espressione, dovrebbero comunque rispettare un determinato ordine di precedenza. Non c'entra niente come viene eseguito effettivamente il codice. C'entra come il codice viene *tradotto*.
Andrea Rimicci
2016-09-19 13:37:47 UTC
Permalink
Post by 4ndre4
Se piu` thread eseguissero pezzi di un'espressione, dovrebbero comunque rispettare
un determinato ordine di precedenza. Non c'entra niente come viene eseguito
effettivamente il codice. C'entra come il codice viene *tradotto*.
Si tratta solo di efficienza. In a + b, non avendo l'obbligo di fare
prima a, posso calcolare a e b contemporaneamente e fare la somma
appena pronti i due risultati, chi è arrivato prima è irrilevante.

Il rispetto di cui parli è comunque corretto in alcuni contesti, per
esempio, l'or logico "a || b || .." del C++ NON valuta 'b' se 'a' è
TRUE, e questo costringe il C++ a valutare prima 'a' e dopo
(eventualmente) 'b' e così via.

Dal punto di vista di un programma 'serializzato', questo è efficiente
perché la valutazione in C++ si ferma non appena il risultato è noto,
e il C invece calcola sempre e comunque tutto, mentre dal punto di
vista 'parallelo' è un handicap perché il C++ è costretto a
serializzare tutte le espressioni una ad una, da sinistra a destra,
mentre il C invece le può valutare tutte in parallelo, non avendo
l'obbligo di fermarsi a risultato finale noto.
--
andrea - ri mi cci, name
4ndre4
2016-09-19 14:30:46 UTC
Permalink
On Monday, 19 September 2016 14:37:48 UTC+1, Andrea Rimicci wrote:

[...]
Post by Andrea Rimicci
Si tratta solo di efficienza.
Non c'entra niente ne` l'efficienza ne` l'elaborazione parallela, con quanto si sta dicendo in questo thread. Tu stai tirando in mezzo i thread, che non c'entrano nulla. Si sta parlando dell'ordine con cui il compilatore traduce gli step di calcolo dell'espressione. In C, esiste il concetto di "sequence point".
enoquick
2016-04-22 12:48:34 UTC
Permalink
Post by Luca
Ciao,
http://i64.tinypic.com/25qf12x.jpg
a= b+= (c++) -d + --e / (-f)
"decremento prefisso" e "-unario" hanno la stessa precenza ma vanno
valutati da destra verso sinistra, giusto?
Poi magari il risultato è uguale, ma a livello concettuale, di regole,
vedo un errore.
Grazie
---
Questa e-mail è stata controllata per individuare virus con Avast antivirus.
https://www.avast.com/antivirus
Qui ha la precedenza degli operatori e la loro associazione

http://it.cppreference.com/w/cpp/language/operator_precedence


E' C++ ma vale anche per il C
ulix
2016-09-10 20:17:47 UTC
Permalink
Guardate, la questione della precedenza degli operatori è
sicuramente fondamentale. L'esempio preso in esame mi sembra più
da IOCCC che altro, una roba così non la userei mai in un
programma reale, spero così anche voi.
--
----Android NewsGroup Reader----
http://usenet.sinaapp.com/

--- news://freenews.netfront.net/ - complaints: ***@netfront.net ---
Loading...