View Full Version : [C] Indovinello trovato in giro
The_ouroboros
21-01-2013, 11:00
Ciao a tutti,
girava stamani in ufficio.
#include<stdio.h>
#define s 65*65*65*65*65
void main()
{
printf("%c",s);
}
Cosa stampa e perchè?
Buon lunedì a tutti.
cdimauro
21-01-2013, 11:24
>>> print chr(65*65*65*65*65 & 0xff)
A
Ovviamente perché l'intero risultante viene troncato alla dimensione del char, che dovrebbe (usualmente, ma non è detto) essere di un byte.
The_ouroboros
21-01-2013, 12:45
>>> print chr(65*65*65*65*65 & 0xff)
A
Ovviamente perché l'intero risultante viene troncato alla dimensione del char, che dovrebbe (usualmente, ma non è detto) essere di un byte.
dioendente dall'endianness mi sembra :stordita:
cdimauro
21-01-2013, 13:48
Purtroppo sì, perché in quella printf il compilatore esegue il push di tutto il valore, che è un intero (1160290625); non sa che in quel posto la funzione si aspetta un char (in realtà in questo caso sì, perché la stringa è costante; ma soprassediamo considerando il caso più generale).
Poi la routine di parsing, facendo la scansione dello stack, in base al template che gli hai passato, carica il valore che gli serve, in base al tipo specificato nel template. E lì possono succedere anche dei disastri.
In realtà il risultato non è garantito nemmeno su un sistema little-endian, perché un compilatore potrebbe avere i char a 16 bit, e quindi caricare 2 byte anziché uno soltanto...
The_ouroboros
21-01-2013, 13:54
interessanti osservazioni.
Mi piaciono queste sottigliezze e curiosità.
Spero di non essere andato troppo oltre ma dati gli ultimi giorni di discussioni su lavoro/uni volevo tornare alla programmazione :D
sottovento
21-01-2013, 14:00
non stampa ovviamente nulla
The_ouroboros
21-01-2013, 14:04
non stampa ovviamente nulla
Su gcc 4.7.2 , debian x64, mi stampa A
The_ouroboros
21-01-2013, 14:08
anche Clang 3.1 su FreeBSD 9.1 x86_64 mi stampa A
sottovento
21-01-2013, 16:22
anche Clang 3.1 su FreeBSD 9.1 x86_64 mi stampa A
Manca ancora qualche sistema da testare :D
Che ne so.... un System V collegato ad un VT52
The_ouroboros
21-01-2013, 16:28
Io quelli ho. :D
Inviato dal mio HUAWEI U8825-1 con Tapatalk 2
banryu79
21-01-2013, 17:31
Manca ancora qualche sistema da testare :D
Che ne so.... un System V collegato ad un VT52
:sbavvv:
:old:
sottovento
22-01-2013, 10:33
:sbavvv:
:old:
Supponi di avere un impianto che ti e' costato milioni di euri. Lo cambi perche' non fa il flush alla print()? :D
Cmq ci sono sistemi anche piu' recenti che si comportano allo stesso modo...
banryu79
22-01-2013, 13:06
Supponi di avere un impianto che ti e' costato milioni di euri. Lo cambi perche' non fa il flush alla print()? :D
Ovviamente no, però questo non cambia il fatto che... :old:
Esticazzi, se permettete :D
sottovento
22-01-2013, 13:25
Ovviamente no, però questo non cambia il fatto che... :old:
Esticazzi, se permettete :D
:D Si, permettiamo.
cmq il risultato potrebbe essere uguale anche su una macchina big endian. O anche no
cdimauro
22-01-2013, 13:49
No, dovrebbe essere 'E'. Sempre nell'ipotesi che venga prelevato un byte per il char.
The_ouroboros
22-01-2013, 13:51
No, dovrebbe essere 'E'. Sempre nell'ipotesi che venga prelevato un byte per il char.
si?
sottovento
22-01-2013, 13:57
No, dovrebbe essere 'E'. Sempre nell'ipotesi che venga prelevato un byte per il char.
Se il compilatore in questione conosce il prototipo della funzione (e supporta, ovviamente, i prototipi), puo' effettuare il cast a char PRIMA di fare il push nello stack. Il cast a char preleva sempre il byte meno significativo, indipendentemente dall'architettura big/little endian, cosi' farebbe il push nello stack della 'A'.
Quanto affermi e' chiaramente vero su compilatori K&R (passami la definizione) poiche' non conoscono nulla della funzione che vai a chiamare e non hanno alternativa a fare il push dei parametri loro passati. Me l'ha detto il mio commercialista :D
cdimauro
22-01-2013, 14:01
si?
Il risultato della moltiplicazione è 0x4528a141. Se prendi il byte più significativo, è 0x45, che in ASCII corrisponde alla E.
Se il compilatore in questione conosce il prototipo della funzione (e supporta, ovviamente, i prototipi), puo' effettuare il cast a char PRIMA di fare il push nello stack. Il cast a char preleva sempre il byte meno significativo, indipendentemente dall'architettura big/little endian, cosi' farebbe il push nello stack della 'A'.
Quanto affermi e' chiaramente vero su compilatori K&R (passami la definizione) poiche' non conoscono nulla della funzione che vai a chiamare e non hanno alternativa a fare il push dei parametri loro passati. Me l'ha detto il mio commercialista :D
Francamente non ricordo questi dettagli, ma mi ero messo nelle condizioni generali (http://www.hwupgrade.it/forum/showpost.php?p=38895117&postcount=4).
The_ouroboros
22-01-2013, 14:02
lucas@lapdog:~$ bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
(65*65*65*65*65)%256
65
cdimauro
22-01-2013, 14:05
Così hai estratto il byte basso.
P.S. bc cos'è?
sottovento
22-01-2013, 14:13
Francamente non ricordo questi dettagli, ma mi ero messo nelle condizioni generali (http://www.hwupgrade.it/forum/showpost.php?p=38895117&postcount=4).
Purtroppo e' il brutto del C: anche un programmino cosi' semplice puo' essere eseguito in maniera completamente diversa a seconda della macchina e del compilatore. E ci si accorge dei problemi sempre troppo tardi. Eppure a prima vista sembra innocuo, un linguaggio come altri...
The_ouroboros
22-01-2013, 14:13
Gnu BC (http://www.gnu.org/software/bc/), arbitrary precision numeric processing language
cdimauro
22-01-2013, 14:30
Grazie. Non ne avevo mai sentito parlare. Strano che abbiano tirato fuori un altro linguaggio, quando con Python si fa lo stesso da tempo (supporta interi di lunghezza arbitraria).
@sottovento: assolutamente d'accordo.
The_ouroboros
22-01-2013, 14:34
Grazie. Non ne avevo mai sentito parlare. Strano che abbiano tirato fuori un altro linguaggio, quando con Python si fa lo stesso da tempo (supporta interi di lunghezza arbitraria).
è comodo come calcolatrice da cli su unix (o almeno io lo uso per quello) :D
cdimauro
22-01-2013, 14:45
Con Python dovresti poterci fare le stesse cose, e ormai non esiste distro o s.o. Unix che non lo abbia già installato.
Comunque è anche una questione di gusti, visto che bc usa la sintassi del C.
The_ouroboros
22-01-2013, 14:52
Con Python dovresti poterci fare le stesse cose, e ormai non esiste distro o s.o. Unix che non lo abbia già installato.
Comunque è anche una questione di gusti, visto che bc usa la sintassi del C.
sono più un tipo da Perl :D
A parte quello, la sintassi C-like non la schifo mai e cmq, come dici tu, è questione di abitudine :stordita:
Vincenzo1968
22-01-2013, 14:58
In C si possono utilizzare un fottìo di librerie gia bell'e pronte. Per esempio, una delle più famose:
http://gmplib.org/
oppure:
http://www.mpfr.org/
;)
The_ouroboros
22-01-2013, 15:01
In C si possono utilizzare un fottìo di librerie gia bell'e pronte. Per esempio, una delle più famose:
http://gmplib.org/
;)
a volte da linea di comando è più comodo lanciare uno scriptino perl da una linea o usare bc e no scomodare il C, imho :fagiano:
Vincenzo1968
22-01-2013, 15:13
a volte da linea di comando è più comodo lanciare uno scriptino perl da una linea o usare bc e no scomodare il C, imho :fagiano:
Ah si si, sicuramente. Anzi, adesso scarico tutto quanto e me lo installo nel mio Linux.
Era solo per dire che non c'è solo python o un qualunque altro linguaggio di alto livello per gestire quei numeri li.
Grazie per il link.
;
The_ouroboros
22-01-2013, 15:15
e io do un occhio alle tue segnalazioni. :)
The_ouroboros
22-01-2013, 15:17
cmq un altra curiosità del linguaggio C è
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 0;
printf("a = %d \n", a);
if(a+1) {}
printf("a+1 in if %d \n", a);
if(a++){}
printf("a++ in if %d \n", a);
return 0;
}
che non è coerente su tutte le piattaforme.
Provate e ditemi :cool:
Vincenzo1968
22-01-2013, 15:22
http://img850.imageshack.us/img850/8062/indovinelloh.jpg
sottovento
22-01-2013, 15:25
In effetti mi aspettavo un output come quello di Vincenzo.
D'accordo che il C e' traditore, ma non vedo inghippi. Cosa ti aspettavi, in realta'?
The_ouroboros
22-01-2013, 15:25
non dovrebbe venire 2 alla fine a?
Invece a+1 viene preso come costante 3 e non modifica a mentre a++ si :D
Lo so che sono cosa sottili e che non saltano fuori così spesso, ma intanto che c'eravamo le ho messe su carta (o schermo, meglio).
The_ouroboros
22-01-2013, 15:28
e su sparc o arm dovrebbe essere diverso il risultato cmq
Vincenzo1968
22-01-2013, 15:30
La macchina è questa:
http://img94.imageshack.us/img94/6105/macchinalinux.jpg
banryu79
22-01-2013, 15:32
non dovrebbe venire 2 alla fine a?
Invece a+1 viene preso come costante 3 e non modifica a mentre a++ si :D
Lo so che sono cosa sottili e che non saltano fuori così spesso, ma intanto che c'eravamo le ho messe su carta (o schermo, meglio).
In C l'espressione "a + 1" non comprende nessuna operazione di assegnazione su 'a', mentre ovviamente "a++" sì: non mi pare che questo si possa annoverare tra le "sottigliezze", anzi tutt'altro direi :mbe:
wingman87
22-01-2013, 15:33
non dovrebbe venire 2 alla fine a?
Invece a+1 viene preso come costante 3 e non modifica a mentre a++ si :D
Lo so che sono cosa sottili e che non saltano fuori così spesso, ma intanto che c'eravamo le ho messe su carta (o schermo, meglio).
Forse hai dimenticato un pezzo di codice? Perché a viene incrementato solo una volta (nella condizione dell'if)
The_ouroboros
22-01-2013, 15:34
In C l'espressione "a + 1" non comprende nessuna operazione di assegnazione su 'a', mentre ovviamente "a++" sì: non mi pare che questo si possa annoverare tra le "sottigliezze", anzi tutt'altro direi :mbe:
era preso da un contesto tipo a=0; b = (a++,a+1,a+2); e vedere cosa è b.
Su sistemi non x86/x64 non è detto che l'ordine sia sx->dx.
Quello era un piccolo particolare :D
Vincenzo1968
22-01-2013, 15:35
http://img197.imageshack.us/img197/3706/indovcomp.jpg
cdimauro
22-01-2013, 15:45
cmq un altra curiosità del linguaggio C è
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 0;
printf("a = %d \n", a);
if(a+1) {}
printf("a+1 in if %d \n", a);
if(a++){}
printf("a++ in if %d \n", a);
return 0;
}
che non è coerente su tutte le piattaforme.
Provate e ditemi :cool:
Questo è sempre corretto.
era preso da un contesto tipo a=0; b = (a++,a+1,a+2); e vedere cosa è b.
Su sistemi non x86/x64 non è detto che l'ordine sia sx->dx.
Quello era un piccolo particolare :D
Questo, invece, dovrebbe dipendere dall'ordine di valutazione delle espressioni, che non è garantito in C.
The_ouroboros
22-01-2013, 15:47
Questo è sempre corretto.
Questo, invece, dovrebbe dipendere dall'ordine di valutazione delle espressioni, che non è garantito in C.
secondo il K&R in ita che ho io dovrebbe essere sx->dx. Però in effetti non dice SEMPRE :)
P.S: se queste cose sono banali o tediose, ditelo :D
Vincenzo1968
22-01-2013, 15:54
Il risultato è corretto.
Se vuoi che stampi 1 nel primo caso devi modificare il codice da così:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 0;
printf("a = %d \n", a);
if(a+1) {}
printf("a+1 in if %d \n", a);
if(a++){}
printf("a++ in if %d \n", a);
return 0;
}
a così:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 0;
printf("a = %d \n", a);
if( a = a+1 ) {}
printf("a+1 in if %d \n", a);
if(a++){}
printf("a++ in if %d \n", a);
}
E, ovviamente, la seconda printf stamperà 2.
;)
cdimauro
22-01-2013, 16:08
secondo il K&R in ita che ho io dovrebbe essere sx->dx. Però in effetti non dice SEMPRE :)
Già. Il compilatore ha la libertà di decidere come valutare le espressioni.
Dovrebbe essere scritto, se non ricordo male, che si vuole essere sicuri di voler preservare l'esatto ordine di valutazione, bisogna ricorrere a delle assegnazioni con variabili di appoggio; ovviamente fuori dalle espressioni (come istruzioni a se stanti).
Comunque il K&R non lo leggo da un pezzo, per cui prendilo con le pinze.
P.S: se queste cose sono banali o tediose, ditelo :D
Ma no, sono interessanti. Altrimenti il thread sarebbe andato deserto. :p
Vincenzo1968
22-01-2013, 16:20
http://img854.imageshack.us/img854/9900/36264976.jpg
http://www.hwupgrade.org/public/style_emoticons/default/coolface.png
banryu79
22-01-2013, 16:27
Prova a confrontarla con questa:
a=0; b = (++a,a+1,a+2);
(Sì, lo so che non dovrebbe cambiare una mazza...)
The_ouroboros
22-01-2013, 16:31
Appena sono a casa provo.. Sono appena uscito dall'ufficio e mi trovo in treno.. :D
Inviato dal mio HUAWEI U8825-1 con Tapatalk 2
Vincenzo1968
22-01-2013, 16:40
int main()
{
int a = 0;
int b = 0;
printf("a = %d \n", a);
a=0; b = (++a,a+1,a+2);
if( a ) {}
printf("a+1 in if %d \n", a);
printf("b = %d \n", b);
if(a++){}
printf("a++ in if %d \n", a);
}
risultato:
a = 0
a+1 in if 1
b = 3
a++ in if 2
Vincenzo1968
22-01-2013, 16:52
Se volete che stampi b = 4 dovete fare così:
b = ( ++a, a = a + 1, a = a + 2 );
The_ouroboros
22-01-2013, 17:10
Interessante.. Grazie x aver proseguito la traccia...:)
Inviato dal mio HUAWEI U8825-1 con Tapatalk 2
Gigibian
24-01-2013, 17:30
dioendente dall'endianness mi sembra :stordita:
Purtroppo sì, perché in quella printf il compilatore esegue il push di tutto il valore, che è un intero (1160290625); non sa che in quel posto la funzione si aspetta un char (in realtà in questo caso sì, perché la stringa è costante; ma soprassediamo considerando il caso più generale).
Poi la routine di parsing, facendo la scansione dello stack, in base al template che gli hai passato, carica il valore che gli serve, in base al tipo specificato nel template. E lì possono succedere anche dei disastri.
In realtà il risultato non è garantito nemmeno su un sistema little-endian, perché un compilatore potrebbe avere i char a 16 bit, e quindi caricare 2 byte anziché uno soltanto...
Supponendo di avere una macchina dove 1 byte=8 bit, il risultato non dovrebbe essere indipendente dall ' endianess ? Non viene cmq stampato l MSB sia che sia a SX che a DX ?
Gigibian
24-01-2013, 17:57
Questo è sempre corretto.
Questo, invece, dovrebbe dipendere dall'ordine di valutazione delle espressioni, che non è garantito in C.
K&R pagina 59: l operatore "comma" valuta da sinistra a destra.
Quindi dovrebbe essere sempre corretto....
Gigibian
24-01-2013, 18:19
Già. Il compilatore ha la libertà di decidere come valutare le espressioni.
Dovrebbe essere scritto, se non ricordo male, che si vuole essere sicuri di voler preservare l'esatto ordine di valutazione, bisogna ricorrere a delle assegnazioni con variabili di appoggio; ovviamente fuori dalle espressioni (come istruzioni a se stanti).
Comunque il K&R non lo leggo da un pezzo, per cui prendilo con le pinze.
Ma no, sono interessanti. Altrimenti il thread sarebbe andato deserto. :p
Non avevo notato che qualcuno l avesse già evidenziato :P.
No cmq l operatore comma, come tutti gli operatori, ha l ordine di valutazione garantito.
Sono alcune espressioni che non è definito come.vengono valutate.
Ad esempio non sai quali parametri.vengono valutati prima in una definizione di funzione:
Func(a,b,c)
Strano, mi sarei aspettato di vedere solo la prima print.
a++ non dovrebbe essere valutato 0 in quel caso (ovvero il valore della variabile corrente)?
Forse fa prima l'incremento e poi valuta l'if sul registro in questione?
Comunque questo è un motivo per cui cerco sempre di esplicitare il più possibile la condizione, evitando cose di quel tipo che possono creare grossi problemi in chi legge :asd: .
cdimauro
24-01-2013, 20:17
Idem. :p
Supponendo di avere una macchina dove 1 byte=8 bit, il risultato non dovrebbe essere indipendente dall ' endianess ? Non viene cmq stampato l MSB sia che sia a SX che a DX ?
No, perché, supponendo che l'intero generato dall'espressione sia a 32 bit, una macchina little-ending esegue il push dei 4 byte sullo stack in ordine inverso rispetto a una big-endian.
Nel momento in cui si referenzia un singolo byte, con una macchina little-endian questo coincide col byte basso dell'intero a 32 bit memorizzato nello stack, mentre per una big-endian corrisponderà a quello alto (da cui il nome, per entrambi).
K&R pagina 59: l operatore "comma" valuta da sinistra a destra.
Quindi dovrebbe essere sempre corretto....
Sì, ho visto che per quest'operatore è garantito.
Non avevo notato che qualcuno l avesse già evidenziato :P.
No cmq l operatore comma, come tutti gli operatori, ha l ordine di valutazione garantito.
No, sono pochi gli operatori per i quali il compilatore garantisce l'ordine di valutazione corretto. Dallo standard ANSI (http://flash-gordon.me.uk/ansi.c.txt):
Except as indicated by the syntax /27/ or otherwise specified later
(for the function-call operator () , && , || , ?: , and comma
operators), the order of evaluation of subexpressions and the order in
which side effects take place are both unspecified.
Sono alcune espressioni che non è definito come.vengono valutate.
Ad esempio non sai quali parametri.vengono valutati prima in una definizione di funzione:
Func(a,b,c)
Sì, è scritto sopra.
Gigibian
24-01-2013, 20:35
Idem. :p
No, perché, supponendo che l'intero generato dall'espressione sia a 32 bit, una macchina little-ending esegue il push dei 4 byte sullo stack in ordine inverso rispetto a una big-endian.
Nel momento in cui si referenzia un singolo byte, con una macchina little-endian questo coincide col byte basso dell'intero a 32 bit memorizzato nello stack, mentre per una big-endian corrisponderà a quello alto (da cui il nome, per entrambi).
Sì, ho visto che per quest'operatore è garantito.
No, sono pochi gli operatori per i quali il compilatore garantisce l'ordine di valutazione corretto. Dallo standard ANSI (http://flash-gordon.me.uk/ansi.c.txt):
Except as indicated by the syntax /27/ or otherwise specified later
(for the function-call operator () , && , || , ?: , and comma
operators), the order of evaluation of subexpressions and the order in
which side effects take place are both unspecified.
Sì, è scritto sopra.
Innanzitutto grazie mille della risposta Cesare :)
tutto chiaro, per quanto riguarda altri gli altri operatori stavo confondendo l' ordine di valutazione con l'associativita che é definita ovviamente x tutti gli operatori :)
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.