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

Ho un problema e vorrei il miglior formalismo per risolverlo:
una funzione dovrebbe ritornare un valore uint32_t (intero unsigned 
range [0 : (2^32)-1]);
esiste tuttavia la necessità di controllare il buon esito di questa e 
segnalare ogni incongruenza con il classico "-1" di errore in uscita; 
mettendo da parte il fatto che *non è assolutamente possibile* che il 
valore di ritorno sia maggiore di 2^31, qual è la soluzione con più 
stile alla cosa nel caso volessi garantire l'utilizzo di tutti i 
(2^32)-1 numeri a disposizione nel caso unsigned?
1)utilizzare come dato di ritorno un int64_t
2)utilizzare come dato di ritorno una struttura
typedef struct{
  uint32_t result
  int8_t check
}struttura;
Nel secondo caso mi verrebbe da pensare che utilizzo comunque 24 bit in 
meno (a meno di discorsi sull'allineamento o dati di supporto alla 
struttura che non so come venga creata in memoria, col c)..
esistono poi altre possibilità per risolvere?
A dire la verità ci sarebbe da dire che la mia funzione dovrebbe sempre 
comunque ritornare un valore >0, pertanto potrei assumere come errore il 
ritorno del valore 0, solo che mi sembra una cosa poco ortodossa e poco 
rispettosa di tutte le altre funzioni che ho fatto rigorosamente 
terminare uscendo con -1 in caso di errore...
Grazie,
InuY4sha :)

Io definirei la funzione come:
int f(uint32_t *val);
Valore di ritorno: int
0 se ok, 1 se non ok.
Argomento: puntatore allo uint32_t che viene modificato.
Piu' elegante di una struttura, piu' portabile.


Io cambierei i valori di ritorno in:  0 se OK e (-1) se KO
per renderlo congruente a quanto fanno la maggioranza delle funzioni 
POSIX.
Ciao
Giovanni
-- 
   A computer is like an air conditioner,
   it stops working when you open Windows.
   Registered Linux user #337974  < 
http://giovanni.homelinux.net/
 >


potresti anche fare un'implementazione simile alla read ad esempio,
che ritorna -1 su errore, se no un numero da 0
a 2^32 - 1;significa usare un int64.
dipende anche se vuoi chiamare la funzione passando un parametro o no!
ciao
davide

 potresti anche fare un'implementazione simile alla read ad esempio,
Direi di evitare implementazioni come read().
Sono purtroppo il tipico bagaglio storico che sarebbe meglio evitare.
Io faccio sempre in modo che il valore di ritorno di una funzione sia
un indicatore di errore, a meno che non ci possano essere errori, o ci
sia un'ovvio valore di errore (tipo 0 per puntatori). Quindi la norma
che io seguo e': ritorna un codice di errore, e modifica i parametri
puntatori come risultati dell'operazione, a meno che:
a) non esistono situazioni di errore
b) c'e' un valore preciso e universale per l'errore, e non ci sono
effetti collaterali.
Quindi i casi a) e b) sono molto pochi in librerie non generali.
Prendi il caso della read().
Storicamente, c'erano due implementazioni: nella prima, in caso di
errore, la read ritornava -1, anche quando solo parte dei dati era
stato trasferito, per esempio a causa di un interruzione.
La seconda tornava il numero di byte trasferiti anche in caso di
errore.
La prima implementazione non funzionava se non potevi fare la seek(),
perche' non potevi cercare di rileggere quello che avevi letto.
La seconda (che e' rimasta), era incompatibile con la prima, quindi
zero portabilita'.
Infatti, se tu usi read(), invece di controllare il codice di errore
(che in alcuni casi puo' non essere irrecuperabile), ti conviene
settare errno a 0, e controllare errno dopo la chiamata di sistema.
Questa e' una tipica situazione dove un codice di errore e un
contatore dei dati letti dovrebbero essere disgiunti.
E non e' un caso atipico.
Per quanto riguarda ritornare -1 e settare errno globale, questa e'
un'altra eredita' che io non sopporto.
C'e' una bellissima cosa che si chiama enum, che facilita la
dichiarazione di errori mutualmente esclusivi.
E si sposa benissimo con codici di errore positivi.
Ecco perche' suggerivo di ritornare 1 invece di -1 in caso di errore.
Se diventa una funzione di libreria, puoi esportare una enum ed
enumerare i tuoi codici di errore.
E con facili macro, puoi shiftare i codici di errore e renderli pure
globali all'applicazione se vuoi.

 (2^32)-1 numeri a disposizione nel caso unsigned?
Devi proprio garantire che _tutti_ i numeri siano restituibili?
Altrimenti puoi riservarti un valore per rappresentare l'errore:
#define ERROR ((uint32_t)-1)
ciao
Giacomo

On Feb 28, 9:59 pm, Giacomo Degli Esposti

La migliore soluzione in questi casi secondo me e':
int foo(uint32_t* return_value)
{
    int error_code = 0;
    /* Fai qualcosa */
    *return_value = /* qualcosa */
    return error_code;
}


Non ti ho seguito moltissimo nel discorso di 1 anzichč -1; avrei usato 
volentieri il -1 per essere coerente con tutte le altre funzioni; in 
ogni caso, dal tuo discorso mi sembra di capire che anzichč utilizzare
	int64_t myfunc(int input);
sarebbe meglio usare
	int8_t myfunc(int input, uint32_t *output);
e generare come ritorno il risultato del controllo, e come valore di 
output il dato in uscita... giusto?

 output il dato in uscita... giusto?
Si.