Newsgroup: it.comp.lang.c
Titolo: unsigned

Ciao a tutti,
sono un novizio e ho un problema:
compilando il programma 
	int main(void)
	{
		unsigned char i = -1;
		printf("%d", i);
	}
ottengo 255.
Con il programma
	int main(void)
	{
		unsigned short i = -1;
		printf("%d", i);
	}
ottengo 65535.
Con il programma
	int main(void)
	{
		unsigned int i = -1;
		printf("%d", i);
	}
ottengo -1.
Con il programma
	int main(void)
	{
		unsigned long i = -1;
		printf("%d", i);	
	}	
ottengo -1.
Perchč con gli ultimi due programmi ottengo -1? se gli interi unsigned
vengono rappresentati in memoria in complemento a 2, non dovrei ottenere
in tutti i casi il max valore rappresentabile? ma allora gli unsigned int
e unsigned long non sono rappresentati in complemento a 2... se č cosě, come vengono
rappresentati?
Grazie.
Angelo

 e unsigned long non sono rappresentati in complemento a 2... se è così,


 rappresentati?
il difetto sta nel fatto che con "unsigned int" e "unsigned long" hai
riempito tutti e 32 i bit che nella tua macchina rappresentano un intero.
dal momento che a printf dici di stampare come intero con segno "%d", non ce
modo per printf di accorgersi della differenza.
mi spiego meglio:
la tua macchina e' sicuramente a 32 bit (deduzione da quel che leggo) per
cui una variabile intera occupa questa grandezza ed e' anche la dimensione
minima di un oggetto passato come parametro ad una funzione, cioe' se hai
una funzione che accetta un parametro char comunque nello stack finiscono 4
byte di cui 3 contengono 0 (o dati casuali).
con unsigned char i = -1;
il compilatore converte automaticamente da char a int (da 8 a 32 bit)
azzerando la parte alta e passando il risultato a printf, quindi vedi
correttamente 255.
idem per unsigned short i = -1; che occupa 16 bit
ma per unsigned int i = -1; che e' gia' grande 32 bit, non ci sono
conversioni e tu a printf hai detto di stamparlo con il segno "%d"
per unsigned long i = -1; il discorso e' diverso in quanto sicuramente un
long e' sulla tua macchina 64bit di cui nella tua printf ne stampi solo i 32
bassi perche' hai usato sempre "%d", ma anche se usavi "%ld" il risultato
non cambiava, devi usare "%lu".
concludendo le variabili signed o unsigned occupano lo stesso spazio di
memoria, quello che cambia e' come interpreti il bit piu' significativo a
livello di compilazione e non di esecuzione.
la printf non puo' sapere (a run-time) come tu hai dichiarato una variabile,
ma glielo devi dire tu nel format string, per gli unsigned usa "%u" per
interi, e "%lu" per long.
ciao
donCiccio

Hei, ma sei sicuro che unsigned long ed unsigned int non sono la stessa cosa? e
cioč interi a 32bit?
da quel che so io:
short int = 16bit
int = long int = 32bit
per interi a 64bit alcuni compilatori usano estensioni come gli __int64 del
visualc++
ma tu che compilatore usi per avere i long int a 64bit?
donCiccio ha scritto:



a dire il vero uso solo il borland per dos dove gli int = short = 16bit e
long = 32bit
cioe' long > int
per cui ho "sparato" 64bit per long
sorry, i'm in error
ciao
donCiccio

 64bit
 
Anche gli unsigned long sono a 32 bit.
 
Ricapitolando:
 
*) se la regola del complemento a due da me riportata č giusta, non c'č
differenza tra il complemento a due di uno e di meno uno (se assegno perň
uno o meno uno ad una variabile unsigned le cose cambiano - come č giusto
che sia)... quindi... la regola da me riportata o č sbagliata o non vale
nel nostro caso. Ma quale č allora quella giusta?
*) se il valore -1 viene memorizzato in una variabile unsigned come
sequenza di uno (come ho letto su "C Didattica e Programmazione, Al
Kelley & Ira Pohl, ADDISON-WESLEY"), non riesco a spiegarmi perchč venga
stampato -1 con gli unsigned int o unsigned long utilizzando "%d" in
printf.
Grazie per l'aiuto.
 
Angelo


perche' con "%d" hai detto a printf di stampare con con segno.
segui questo ragionamento e forse il concetto di complemento a due e numeri
negativi ti verra' piu' facile.
supponiamo per semplicita' di avere una variabili di ampiezza 3bit, ci posso
memorizzare 16 combinazioni binarie da 000 a 111 da 0 a 7 in decimale.
immagina che sia un'entita' circolare cioe' se continuo a sommare 1 passo da
111 a 000, cioe' do il giro.
se lo considero circolare allora se sottraggo 1 da 000 passo a 111, quindi
in decimale 0 - 1 = -1
quindi -1 = 111 binario
se sottraggo ancora 1 a 111 ottengo 110, cioe' -1 - 1 =-2, e via cosi' fino
a 100 che corrisponde a -4
bin    u    s
000   =0    0
001    1    1
010    2    2
011    3    3
100    4   -4
101    5   -3
110    6   -2
111    7   -1
come vedi il bit piu' significativo e' alto per i valori negativi, cioe'
indica il segno, ma per passare da positivo a negativo, non devi
semplicemente accenderlo e spegnerlo, vanno campiati anche gli altri bit.
perche' esprimere cosi' i numeri negativi? per semplicita' della cpu che non
deve fare nulla di diverso se i numeri sono positivi o negativi. supponiamo
l'operazione -1 + 2 = 1
in binario la cpu fa una addizione normale tra 111 e 010 come se stesse
sommando 7 + 2, ottenendo 001 con riporto di 1
il complemento a 2 e' il metodo con cui ricavi il valore binario di un
numero negativo partendo dal suo valore assoluto, in modo che segua la
tabella che ti ho scritto prima.
ciao
donCiccio

rappresentati?
Che confusione.
I numeri negativi vengono rappresentati comunque in complemento a 2
(non e' detto che si usi sempre il complemento a 2).  
Non c'entra la natura signed/unsigned della variabile che li contiene.
Il valore che vedi a video e' frutto dello specificatore di formato
utilizzato per stampare il numero.
Se usi %d allora viene considerato il segno, se usi %u no.
Tutto qui.

printf.
Ripeto : -1 in memoria viene COMUNQUE memorizzato in complemento a 2,
sia la variabile che lo contiene signed o unsigned.
E' quando lo vai a stampare che, secondo lo specificatore di formato,
comunichi a printf di considerare o meno il segno.

memorizzare 16 combinazioni binarie da 000 a 111 da 0 a 7 in decimale.
Se i valori vanno da 0 a 7 non capisco come possano essere 16
combinazioni.
Con 3 bit, le combinazioni sono 2^3 = 8 (appunto da 0 a 7).
E' con 4 bit che se ne rappresentano 16.

 E' con 4 bit che se ne rappresentano 16.
opss, mi e' sfuggito un 16 perche' avevo iniziato a scrivere la tabella con
4 bit, ma veniva troppo lunga...
bye
donCiccio

 quindi non c'e' alcuna promozione al tipo superiore.
e questa chi te l'ha detta?
il byte e' 8 bit per definizione, non per convenienza.
e un char e' grande un byte sempre per definizione.
tutto cio' che e' inferiore alla dimensione di un int, viene promosso ad
essere un int durante il passaggio dei parametri ad una funzione, perche'
l'int e' impostato alla dimensione minima del dato macchina, cioe' la tua
cpu non puo' "pushare" nello stack oggetti piu' piccoli.
provati questo esempio
void fun ( char a,char b )
{
  printf( "         &a=%p\n",&a );
  printf( "         &b=%p\n",&b );
  printf( "  diff(b-a)=%d\n",&b-&a );
  printf( "sizeof(int)=%d\n",sizeof(int) );
}
int main ( void )
{
  fun( 0,0 );
  return 0;
}
ciao
donCiccio

dalle macchine cosi' come te l'ho descritto, cioe' con una somma.
Il nostro amico, evidentemente, lo sta calcolando a mano ed il
procedimento, nell'uno o nell'altro caso e' perfettamente equivalente.

 ha scritto nel messaggio
news:3ae9558a...@news.libero.it...

secondo me, anche facendolo a mano e' piu' facile fare una somma che una
sottrazione.
ciao
donCiccio

cpu non puo' "pushare" nello stack oggetti piu' piccoli.
Questo non vuol dire nulla.
All'interno della funzione, il mio parametro viene trattato come char,
escludendo quindi i byte che non servono.

>l'int e' impostato alla dimensione minima del dato macchina, 
Aggiungo una cosa :
Stai confondendo tra cio' che e' il passaggio di un "char" ad una
funzione che accetta un "char" ed il passaggio di un "char" ad una
funzione che NON SA di accettare un char.
Nel caso di printf il numero e il tipo di parametri non e' conosciuto
ed e' normale, quindi, che vi sia promozione di tipi.
Ma non vale lo stesso discorso per tutte le funzioni.

 Ma non vale lo stesso discorso per tutte le funzioni.
se intendi dire che i parametri passati alle funzioni occupano nello stack
la dimensione di un int come minimo, si vale per tutte le funzioni.
se intendi la conversione automatica da unsigned char a int, io stavo
spiegando come avveniva il passaggio alla printf dell'esempio, e quindi e'
giusto quello che ho scritto.
ciao
donCiccio

 no un byte e' sempre 8 bit, una word dipende dalla macchina.
guarda, non ho lo std C99, ma in quello del C++ non si nomina mai 
esplicitamente la lunghezza del byte... suppongo sia la stessa cosa nel 
C. 

giusto quello che ho scritto.
Ah be, allora non ti riferire a "le funzioni" in generale...

C. 
Difatti la dimensione di un byte non e' fissabile a priori.

 L'informatica sfrutta concetti matematici, non accade viceversa.
scusa la mia ignoranza, perche' probabilmente di quello si tratta, ma in
matematica esiste il segno meno per indicare i numeri negativi, in
elettronica/informatica no e si usa il complemento a 2.
matematicamente che senso ha dire che 77 e' il complemento a 2 di 23
cioe' -23 ? (i numeri si riferiscono al tuo esempio).
sei proprio sicuro che il complemento a 2 non e' stato inventato quando e'
nata l'elettronica digitale, proprio per rappresentare i numeri negativi in
un sistema che non prevede altri segni olre alle cifre?
poi ripeto cio' che a suo tempo mi avevano insegnato (per base 2):
complenento a 2 di X = complemento a 1 di X + 1
complemento a 1 di X = complemento dei singoli bit che compongono X
complemento di un bit = l'opposto del suo valore
ciao
donCiccio
PS
forse il tono dei miei post puo' sembrare aggressivo, me ne scuso, ma non
sono cattivo

 wrote:

nello standard C++ si dice che un char è lungo almeno 8 bit. C'è un
thread in corso si iclc++
Anto
--
Antonio Cuni, 18 anni, studente
Brainbench Certification: 
Master C++: 4.6, higher than 98% of all previous test takers.
C Language: 3.32, higher than 79% of all previous test takers.
http://www.brainbench.com/transcript.jsp?pid=1301688

un sistema che non prevede altri segni olre alle cifre?
Il complemento a 2 non e' stato INVENTATO con l'elettronica digitale.
E' stato solo SFRUTTATO, in quanto concetto matematico di partenza.