Domanda Risolto [C] Esercizio

nostyn

Utente Electrum
12 Gennaio 2017
284
25
83
126
Ultima modifica:
Questo programma serve per poter ricavare il range di valori contenuti all'interno di una variabile di un determinato tipo, senza fare riferimento alla libreria limits.h :

C:
#include <stdio.h>

void printDim(short nBytes, int Signed);

int main()
{
    printf("Signed Char dim:\n");
    printDim(1,1);
    printf("Signed Short dim:\n");
    printDim(2,1);
    printf("Signed Long dim:\n");
    printDim(4,1);
    printf("Unsigned Char dim:\n");
    printDim(1,0);
    printf("Unsigned Short dim:\n");
    printDim(2,0);
    printf("Unsigned Long dim:\n");
    printDim(4,0);
    return 0;
}

void printDim(short nBytes, int Signed)
{
    nBytes *= 8; //Trasformo i bytes in bits
    unsigned long max = 1;
 
    for(int i = 0;i < nBytes;i++)
    {
        if((i + 1) == nBytes)   //Se si tratta dell'ultimo bit
            max = ((max - 1) * 2) +1;   //Per evitare che l'ultimo valore superi la dimensione del suo contenitore mi assicuro che arrivi precisamente all'ultimo numero che può contenere un unsigned long.
        else
            max *= 2;
    }
 
    signed long minVal = ( Signed == 1 ) ? -((max/2)+1) : 0;
    unsigned long maxVal = ( Signed == 1 ) ? max/2 : max;
 
    printf("FROM %10lu\n  TO %10lu\n\n",minVal,maxVal);
}
1549824555058.png

Sto cercando una soluzione a questo problema, non saprei come effettuare correttamente la conversione da unsigned a signed in questa espressione. So che una possibile soluzione per quello che devo fare è inserire il meno direttamente sotto forma di testo nel printf e poi inserire come parametro il resto dell'espressione ma volevo riuscire a inserirlo all'interno di una variabile questo valore. Grazie in anticipo per le risposte!
 
Per prima cosa usare la parola chiave signed accanto il tipo long, è inutile dal momento che signed è di default per la long.
Seconda cosa:
Codice:
    printf("FROM %10lu\n  TO %10lu\n\n",minVal,maxVal);
Diventa:
Codice:
    printf("FROM %10ld\n  TO %10lu\n\n",minVal,maxVal);

Fammi sapere
 
  • Mi piace
Reazioni: nostyn
Per prima cosa usare la parola chiave signed accanto il tipo long, è inutile dal momento che signed è di default per la long.
Seconda cosa:
Codice:
    printf("FROM %10lu\n  TO %10lu\n\n",minVal,maxVal);
Diventa:
Codice:
    printf("FROM %10ld\n  TO %10lu\n\n",minVal,maxVal);

Fammi sapere
Sisi so che è sotto intesto, ma nella disperazione per risolvere il problema le ho provate tutte, anche dichiararlo esplicitamente ahaha
Ho risolto il problema in mattinata, non ho avuto il tempo di editare il post :D In ogni caso grazie per aver risposto. Mi ha funzionato con con solo %10d, dunque quell' "ld" cosa dovrebbe variare?
 
Mi ha funzionato con con solo %10d, dunque quell' "ld" cosa dovrebbe variare?
Semplicemente con d stai indicando alla funzione printf che si tratta di un int, con ld di un long int. l è lo specificatore di lunghezza.
Nel caso in cui una variabile di tipo long int dovesse contenere un valore maggiore o minore dei limiti di int (perfettamente lecito) quando printf viene invocata con lo specificatore di conversione d si aspetta valori nei limiti di int, ma nel nostro caso long int contiene un valore maggiore/minore dei limiti di int quindi si verifica un undefined behaviour. Lo C standard dice: If a conversion specification is invalid, the behavior is undefined. If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
Fonte: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf Capitolo 7.19.6 Formatted input/output functions punto 9

E' buona norma usare lo specificatore uguale al tipo di dato da stampare: http://www.cplusplus.com/reference/cstdio/printf/
 
  • Mi piace
Reazioni: nostyn
Semplicemente con d stai indicando alla funzione printf che si tratta di un int, con ld di un long int. l è lo specificatore di lunghezza.
Nel caso in cui una variabile di tipo long int dovesse contenere un valore maggiore o minore dei limiti di int (perfettamente lecito) quando printf viene invocata con lo specificatore di conversione d si aspetta valori nei limiti di int, ma nel nostro caso long int contiene un valore maggiore/minore dei limiti di int quindi si verifica un undefined behaviour. Lo C standard dice: If a conversion specification is invalid, the behavior is undefined. If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
Fonte: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf Capitolo 7.19.6 Formatted input/output functions punto 9

E' buona norma usare lo specificatore uguale al tipo di dato da stampare: http://www.cplusplus.com/reference/cstdio/printf/

Conoscevo la differenza tra ld e d, ma questa precisazioni mi tornerà molto utile, grazie mille!
Dunque nel caso non specifico "long" è a discrezione del compilatore eseguire un "cast" implicito, giusto?
 
Ultima modifica:
Dunque nel caso non specifico "long" è a discrezione del compilatore eseguire un "cast" implicito, giusto?
Molto banalmente e a grandi linee si.

Comunque è buona norma e ti consiglio personalmente di usare sempre lo specificatore corrispondente per evitare errori subdoli difficilmente riconoscibili, ad esempio printf stampa valori "sballati" ma il codice è tutto esatto e non riesci a capire il problema, poi quando si lavora su tabelle dove ci sono molti valori da stampare (non solo 2), diventa molto complesso trovare errori nei printf.

Se non li ricordi fai riferimento alla pagina (quella di prima) http://www.cplusplus.com/reference/cstdio/printf/.
 
  • Mi piace
Reazioni: °DarknesS°
the behavior is undefined.
Vorrei dire due parole a riguardo di questa terminologia che spesso leggo nei forum.
Undefined behavior = Comportamento imprevisto.
Si possono avere decine e decine di situazioni che portano e/o causano un comportamento imprevisto.
Sostanzialmente, se in fase di compilazione e linking non abbiamo errori NON vuol dire che non ci siano comportamenti imprevisti.
Maggiore aumenta la complessità di un software maggiore sarà la possibilità di generare un comportamento imprevisto.
Dunque un undefined behavior non è nulla di alieno, ma un qualcosa che tutti hanno avuto modo di sperimentare almeno una volta, consapevolmente o meno.
Per il resto, d'accordissimo.
 
  • Mi piace
Reazioni: °DarknesS°
Vorrei dire due parole a riguardo di questa terminologia che spesso leggo nei forum.
Undefined behavior = Comportamento imprevisto.
Si possono avere decine e decine di situazioni che portano e/o causano un comportamento imprevisto.
Sostanzialmente, se in fase di compilazione e linking non abbiamo errori NON vuol dire che non ci siano comportamenti imprevisti.
Maggiore aumenta la complessità di un software maggiore sarà la possibilità di generare un comportamento imprevisto.
Dunque un undefined behavior non è nulla di alieno, ma un qualcosa che tutti hanno avuto modo di sperimentare almeno una volta, consapevolmente o meno.
Per il resto, d'accordissimo.
Non è esattamente così, undefined behavior letteralmente significa comportamento non definito ed è qualcosa da evitare assolutamente, molto probabilmente per chi è alle prime armi può succedere (anche a me è successo e succede) di riscontrare comportamenti indefiniti ma come si diventa più esperti diventa inaccettabile, ovviamente gli undefined behavior non sono "confinati" solo nei printf o scanf. Non voglio inventarmi nulla quindi quoto la documentazione C++:
  • undefined behavior - there are no restrictions on the behavior of the program. Examples of undefined behavior are memory accesses outside of array bounds, signed integer overflow, null pointer dereference, modification of the same scalar more than once in an expression without sequence points, access to an object through a pointer of a different type, etc. Compilers are not required to diagnose undefined behavior (although many simple situations are diagnosed), and the compiled program is not required to do anything meaningful.
https://en.cppreference.com/w/cpp/language/ub
Quindi il programma come hai detto viene compilato correttamente ma non è assicurato il perfetto funzionamento, può essere che in alcuni casi il programma funzioni correttamente ed in altri no.
Sfortunatamente non è sempre facile riconoscere questi tipi di problemi, soprattutto per chi è meno esperto.