Oppure

Loading
30/04/17 22:23
AldoBaldo
Ciao a te che leggi.

Oggi non sapevo che fare e ho messo insieme una paginata di roba in previsione di un futuro ed ipotetico uso personale. Probabilmente si tratta della classica "reinvenzione della ruota", però sapete che son fatto così e che mi diverto a scrivere 'ste cose. Non escludo che si tratti pure di un modo improprio di ottenere il risultato.

Detto questo... potrebbe essere utile aggiungere questi file alla sezione "esempi" dei programmi presenti su Pierotofy? Se sì, aggiungo; se no, tengo per me. Graditi opinioni e, se non significano "rivoluzionare" tutto (non ne vale la pena, credo), suggerimenti su come migliorare il codice. Meno gradito, ma comunque accettato, un eventuale "ma piantala lì!".

Tre file. Il primo: numeri_e_stringhe.h

/**=============================================================================
                               NUMERI E STRINGHE
                               v1.0 - aprile 2017

Gestisce valori compresi tra 9223372036854775807 e -9223372036854775807 (interi
a 64 bit) con base compresa tra 2 e 36.
=============================================================================**/

#ifndef NUMERI_E_STRINGHE_H_INCLUDED
#define NUMERI_E_STRINGHE_H_INCLUDED

/** ===> INCLUSIONI <========================================================**/

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>  /* per usare i tipi uint64_t, int64_t, int16_t e int8_t */
#include <stdbool.h> /* per usare il tipo bool */
#include <ctype.h>   /* per usare tolower() e toupper() */

/** ===> MACRO <============================================================ **/

#define NS_USACHIEDINUMERO    /* da definire per usare NS_chiedi_numero() */
#define NS_CIFRANONVALIDA  -1 /* restituito come errore da NS_cifra() */
#define NS_MINBASE          2 /* la base non puo' essere inferiore */
#define NS_MAXBASE         36 /* la base non puo' essere superiore */
#define NS_MINVAL          -9223372036854775807LL
#define NS_MAXVAL           9223372036854775807LL
#define NS_DIMBUFFNUM      68 /* le dimensioni del buffer per la
                                 rappresentazione dei numeri a 64 bit
                                 sotto forma di stringa */

/** ===> PROTOTIPI DELLE FUNZIONI <========================================= **/

#ifdef NS_USACHIEDINUMERO
int64_t NS_chiedi_numero( int64_t minimo, int64_t massimo, int8_t base );
#endif // NS_USACHIEDINUMERO

int64_t NS_sn( const char *s, int16_t *qCifre, int8_t base );
char *NS_ns( int64_t n, char *buff, int8_t base );
int8_t NS_cifra( char c, int8_t base );
void NS_usa_cifre_maiuscole( bool usa_cifre_maiuscole );

#endif /* NUMERI_E_STRINGHE_H_INCLUDED */


Il secondo: numeri_e_stringhe.c

/**=============================================================================
                               NUMERI E STRINGHE
                               v1.0 - aprile 2017

Gestisce valori compresi tra 9223372036854775807 e -9223372036854775807 (interi
a 64 bit) con base compresa tra 2 e 36.
=============================================================================**/

#include "numeri_e_stringhe.h"

/** ===> COSTANTI <========================================================= **/

static const char *NS_Cifre = "0123456789abcdefghijklmnopqrstuvwxyz";
static const char NS_SegnoNegativo = '-';
static const char *NS_StrErrBaseNonValida = "(la base eccede i limiti)";

/** ===> VARIABILI GLOBALI PER QUESTO FILE <================================ **/

bool NS_usa_maiuscole = false;

/** ===> DEFINIZIONE DELLE FUNZIONI <======================================= **/

/*==============================================================================
Chiede l'immissione in console di un numero intero compreso tra min e max, dove
min non puo' essere inferiore a NS_MINVAL e max non puo' essere superiore a
NS_MAXVAL. Restituisce il numero immesso come valore di ritorno di tipo int64_t.
La funzione insiste nella sua richiesta fintanto che non viene immesso un dato
accettabile, quindi ritorna.
Per usare questa funzione occorre che sia definita la macro NS_USACHIEDINUMERO.
==============================================================================*/

#ifdef NS_USACHIEDINUMERO
int64_t NS_chiedi_numero( int64_t min, int64_t max, int8_t base ) {
    char buff[NS_DIMBUFFNUM]; /* 64 cifre + il segno negativo */
    bool ripeti, pp = true; /* pp = primo passaggio */
    int16_t l, qCifre;
    int64_t n;

    do {
        if( !pp ) /* se non e' il primo passaggio... */
            printf( "Input non valido, riprova: " );
        else pp = false; /* se e' il primo passaggio */

        fgets( buff, NS_DIMBUFFNUM, stdin ); /* riceviamo l'input */
        for( l=0; buff[l]; ++l ); /* la lunghezza dell'input */

        if( buff[l-1] == '\n' ) {
            n = NS_sn( buff, &qCifre, base ); /* converte in int64_t */
            ripeti = n<min || n>max || qCifre==0;
        }
        else {
            /* se l'ultimo carattere non e' '\n' significa che
               l'input e' stato troncato, il che non va bene;
               eliminiamo i caratteri ancora "pendenti" */
            while( getchar() != '\n' );
            ripeti = true; /* la condizione per ripetere */
        }
    } while( ripeti );

    return n; /* restituisce il numero immesso */
}
#endif // NS_USACHIEDINUMERO

/*==============================================================================
Converte una stringa nel numero intero corrispondente, secondo la base di
numerazione specificata.
Se la stringa inizia con caratteri non idonei a rappresentare le cifre del
sistema di numerazione specificato, quei caratteri non vengono considerati.
Se la stringa contiene una rappresentazione numerica valida, la funzione
restituisce il valore ricavato dalla stringa (in formato int64_t) e immette la
quantita' delle cifre riconosciute all'indirizzo indicato dal parametro qCifre.
Se la stringa NON contiene una rappresentazione numerica valida, la funzione
restituisce 0 e immette 0 anche all'indirizzo indicato dal parametro qCifre.
Se il parametro qCifre e' un puntatore NULL, la funzione non puo' fornire
informazioni circa la quantita' di cifre riconosciute, rendendo di fatto
impossibile al chiamante sapere se la conversione e' stata portata a termine
correttamente oppure no.
==============================================================================*/

int64_t NS_sn( const char *s, int16_t *qCifre, int8_t base ) {
    int16_t totCifre = 0; /* si presuppone il fallimento */
    int64_t r = 0; /* il risultato dell'operazione */

    /* se i parametri sono accettabili, analizziamo la stringa */
    if( s != NULL && (base>=NS_MINBASE&&base<=NS_MAXBASE) ) {
        const char *p = s; /* puntatore ausiliario */
        bool negativo;

        /* scartiamo tutti i caratteri non numerici iniziali */
        while( !(NS_cifra(*p,base)>=0||*p==NS_SegnoNegativo) && *p!='Ciao a te che leggi.


Oggi non sapevo che fare e ho messo insieme una paginata di roba in previsione di un futuro ed ipotetico uso personale. Probabilmente si tratta della classica "reinvenzione della ruota", però sapete che son fatto così e che mi diverto a scrivere 'ste cose. Non escludo che si tratti pure di un modo improprio di ottenere il risultato.

Detto questo... potrebbe essere utile aggiungere questi file alla sezione "esempi" dei programmi presenti su Pierotofy? Se sì, aggiungo; se no, tengo per me. Graditi opinioni e, se non significano "rivoluzionare" tutto (non ne vale la pena, credo), suggerimenti su come migliorare il codice. Meno gradito, ma comunque accettato, un eventuale "ma piantala lì!".

Tre file. Il primo: numeri_e_stringhe.h

/**=============================================================================
                               NUMERI E STRINGHE
                               v1.0 - aprile 2017

Gestisce valori compresi tra 9223372036854775807 e -9223372036854775807 (interi
a 64 bit) con base compresa tra 2 e 36.
=============================================================================**/

#ifndef NUMERI_E_STRINGHE_H_INCLUDED
#define NUMERI_E_STRINGHE_H_INCLUDED

/** ===> INCLUSIONI <========================================================**/

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>  /* per usare i tipi uint64_t, int64_t, int16_t e int8_t */
#include <stdbool.h> /* per usare il tipo bool */
#include <ctype.h>   /* per usare tolower() e toupper() */

/** ===> MACRO <============================================================ **/

#define NS_USACHIEDINUMERO    /* da definire per usare NS_chiedi_numero() */
#define NS_CIFRANONVALIDA  -1 /* restituito come errore da NS_cifra() */
#define NS_MINBASE          2 /* la base non puo' essere inferiore */
#define NS_MAXBASE         36 /* la base non puo' essere superiore */
#define NS_MINVAL          -9223372036854775807LL
#define NS_MAXVAL           9223372036854775807LL
#define NS_DIMBUFFNUM      68 /* le dimensioni del buffer per la
                                 rappresentazione dei numeri a 64 bit
                                 sotto forma di stringa */

/** ===> PROTOTIPI DELLE FUNZIONI <========================================= **/

#ifdef NS_USACHIEDINUMERO
int64_t NS_chiedi_numero( int64_t minimo, int64_t massimo, int8_t base );
#endif // NS_USACHIEDINUMERO

int64_t NS_sn( const char *s, int16_t *qCifre, int8_t base );
char *NS_ns( int64_t n, char *buff, int8_t base );
int8_t NS_cifra( char c, int8_t base );
void NS_usa_cifre_maiuscole( bool usa_cifre_maiuscole );

#endif /* NUMERI_E_STRINGHE_H_INCLUDED */


Il secondo: numeri_e_stringhe.c

/**=============================================================================
                               NUMERI E STRINGHE
                               v1.0 - aprile 2017

Gestisce valori compresi tra 9223372036854775807 e -9223372036854775807 (interi
a 64 bit) con base compresa tra 2 e 36.
=============================================================================**/

#include "numeri_e_stringhe.h"

/** ===> COSTANTI <========================================================= **/

static const char *NS_Cifre = "0123456789abcdefghijklmnopqrstuvwxyz";
static const char NS_SegnoNegativo = '-';
static const char *NS_StrErrBaseNonValida = "(la base eccede i limiti)";

/** ===> VARIABILI GLOBALI PER QUESTO FILE <================================ **/

bool NS_usa_maiuscole = false;

/** ===> DEFINIZIONE DELLE FUNZIONI <======================================= **/

/*==============================================================================
Chiede l'immissione in console di un numero intero compreso tra min e max, dove
min non puo' essere inferiore a NS_MINVAL e max non puo' essere superiore a
NS_MAXVAL. Restituisce il numero immesso come valore di ritorno di tipo int64_t.
La funzione insiste nella sua richiesta fintanto che non viene immesso un dato
accettabile, quindi ritorna.
Per usare questa funzione occorre che sia definita la macro NS_USACHIEDINUMERO.
==============================================================================*/

#ifdef NS_USACHIEDINUMERO
int64_t NS_chiedi_numero( int64_t min, int64_t max, int8_t base ) {
    char buff[NS_DIMBUFFNUM]; /* 64 cifre + il segno negativo */
    bool ripeti, pp = true; /* pp = primo passaggio */
    int16_t l, qCifre;
    int64_t n;

    do {
        if( !pp ) /* se non e' il primo passaggio... */
            printf( "Input non valido, riprova: " );
        else pp = false; /* se e' il primo passaggio */

        fgets( buff, NS_DIMBUFFNUM, stdin ); /* riceviamo l'input */
        for( l=0; buff[l]; ++l ); /* la lunghezza dell'input */

        if( buff[l-1] == '\n' ) {
            n = NS_sn( buff, &qCifre, base ); /* converte in int64_t */
            ripeti = n<min || n>max || qCifre==0;
        }
        else {
            /* se l'ultimo carattere non e' '\n' significa che
               l'input e' stato troncato, il che non va bene;
               eliminiamo i caratteri ancora "pendenti" */
            while( getchar() != '\n' );
            ripeti = true; /* la condizione per ripetere */
        }
    } while( ripeti );

    return n; /* restituisce il numero immesso */
}
#endif // NS_USACHIEDINUMERO

/*==============================================================================
Converte una stringa nel numero intero corrispondente, secondo la base di
numerazione specificata.
Se la stringa inizia con caratteri non idonei a rappresentare le cifre del
sistema di numerazione specificato, quei caratteri non vengono considerati.
Se la stringa contiene una rappresentazione numerica valida, la funzione
restituisce il valore ricavato dalla stringa (in formato int64_t) e immette la
quantita' delle cifre riconosciute all'indirizzo indicato dal parametro qCifre.
Se la stringa NON contiene una rappresentazione numerica valida, la funzione
restituisce 0 e immette 0 anche all'indirizzo indicato dal parametro qCifre.
Se il parametro qCifre e' un puntatore NULL, la funzione non puo' fornire
informazioni circa la quantita' di cifre riconosciute, rendendo di fatto
impossibile al chiamante sapere se la conversione e' stata portata a termine
correttamente oppure no.
==============================================================================*/

int64_t NS_sn( const char *s, int16_t *qCifre, int8_t base ) {
    int16_t totCifre = 0; /* si presuppone il fallimento */
    int64_t r = 0; /* il risultato dell'operazione */

    /* se i parametri sono accettabili, analizziamo la stringa */
    if( s != NULL && (base>=NS_MINBASE&&base<=NS_MAXBASE) ) {
        const char *p = s; /* puntatore ausiliario */
        bool negativo;

        /* scartiamo tutti i caratteri non numerici iniziali */
        while( !(NS_cifra(*p,base)>=0||*p==NS_SegnoNegativo) && *p!='{parsed_message}' ) ++p;

        if( *p != '{parsed_message}' ) { /* se sono rimasti caratteri */
            int16_t i, j; /* contatori */

            if( (negativo=*p==NS_SegnoNegativo) ) ++p; /* saltiamo il segno */
            while( *p == '0' ) ++p; /* saltiamo gli zeri iniziali */

            while( NS_cifra(p[totCifre],base) >= 0 ) /* contiamo le cifre */
                ++totCifre;

            if( totCifre > 0 ) { /* se ci sono cifre valide, calcoliamo */
                for( i=totCifre; i>0; --i ) { /* partendo dal fondo */
                    int64_t tmp=1;
                    for( j=0; j<totCifre-i; ++j ) tmp *= base; /* potenza */
                    r += NS_cifra(p[i-1],base) * tmp;
                }

                if( negativo ) r = -r; /* se era negativo, ripristiniamo */
            }
        }
    }

    if( qCifre != NULL ) *qCifre = totCifre; /* solo se non e' NULL */

    return r;
}

/*==============================================================================
Converte un numero intero in formato int64_t nella sua rappresentazione in forma
di stringa, secondo la base di numerazione specificata.
Se il parametro buff e' un puntatore valido, la funzione impiega lo spazio di
memoria puntato per collocarvi la stringa risultante dalla conversione. Spetta
al chiamante assicurarsi che buff punti a uno spazio di memoria sufficiente per
contenere la stringa (il caso piu' "esigente" riguarda il valore a 64 bit
massimo in formato binario: 64 caratteri piu' il terminatore, eventualmente con
l'aggiunta d'un segno negativo -- 66 caratteri in tutto).
Se il parametro buff e' NULL, la funzione inserisce la stringa risultante in un
buffer statico costituito da NS_DIMBUFFNUM char. Ovviamente, ogni nuova chiamata
alla funzione sovrascrive il buffer cancellando l'esito delle eventuali
conversioni precedenti.
La funzione fallisce (restituendo una stringa che descrive l'errore) solo se
il parametro base eccede i limiti consentiti da NS_MINBASE e NS_MAXBASE.
==============================================================================*/

char *NS_ns( int64_t n, char *buff, int8_t base ) {
    static char sBuff[NS_DIMBUFFNUM]; /* max 64 cifre + il segno negativo */
    uint64_t un; /* necessario per il valore negativo minimo */
    int16_t i; /* deve poter contenere almeno la lunghezza della stringa */

    /* se il parametro buff e' nullo, usiamo il buffer statico */
    if( buff == NULL ) buff = sBuff;

    if( base>=NS_MINBASE && base<=NS_MAXBASE ) {
        int16_t l, lMezzi;
        bool negativo;
        int8_t cifra;

        negativo = n < 0; /* memorizziamo il segno */
        un = negativo ? -n : n; /* usiamo sempre un valore positivo */

        /* N.B. la stringa viene generata "all'indietro" */
        for( l=0; un!=0; ++l ) {
            cifra = un%base;
            buff[l] = NS_Cifre[cifra];
            un /= base;
        }

        if( negativo ) buff[l++] = NS_SegnoNegativo; /* apponiamo il segno? */
        buff[l] = '{parsed_message}'; /* terminiamo la stringa */

        /* "rovesciamo" la stringa (generata all'indietro) */
        for( lMezzi=l/2, i=0; i<lMezzi; ++i ) {
            char aux = buff[i];
            buff[i] = buff[l-i-1];
            buff[l-i-1] = aux;
        }

        /* se necessario, usiamo le cifre in caratteri maiuscoli */
        if( NS_usa_maiuscole )
            for( i=0; i<l; ++i )
                buff[i] = toupper( buff[i] );
    }
    else { /* la base eccede i limiti imposti da NS_MINBASE e NS_MAXBASE */
        for( i=0; NS_StrErrBaseNonValida[i]; ++i )
            buff[i] = NS_StrErrBaseNonValida[i]; /* copiamo l'errore */
        buff[i] = '{parsed_message}'; /* terminiamo la stringa */
    }

    return buff; /* restituiamo un puntatore al buffer effettivamente usato */
}

/*==============================================================================
Verifica se c corrisponde a una delle cifre valide nel sistema di numerazione
che impiega la base specificata dal parametro base. Se c e' una cifra valida
restituisce il valore della cifra; se c NON e' una cifra valida restituisce
NS_CIFRANONVALIDA.
==============================================================================*/

int8_t NS_cifra( char c, int8_t base ) {
    c = tolower(c);
    int8_t i;

    if( base>=NS_MINBASE && base<=NS_MAXBASE )
        for( i=0; i<base; ++i )
            if( c == NS_Cifre[i] )
                return i;
    return NS_CIFRANONVALIDA;
}

/*==============================================================================
Imposta una variabile statica che fa si' che le altre funzioni impieghino (nelle
chiamate successive) caratteri maiuscoli o minuscoli come cifre per quei sistemi
di numerazione che richiedono l'uso di oltre 10 cifre.
==============================================================================*/

void NS_usa_cifre_maiuscole( bool usa_cifre_maiuscole ) {
    NS_usa_maiuscole = usa_cifre_maiuscole;
}


Il terzo, con un programmino d'esempio d'uso: main.c

/**=============================================================================
Programma d'esempio per numeri_e_stringhe.
=============================================================================**/

#include <string.h>
#include "numeri_e_stringhe.h"

int main() {
    char buff[NS_DIMBUFFNUM];
    int8_t b1, b2;
    int64_t n;
    bool ripeti;

    printf( "CONVERTE LA BASE DI NUMERAZIONE DI UN NUMERO DATO\n" );
    printf( "=================================================\n\n" );

    do {
        printf( "Immetti la base di numerazione iniziale (%d-%d): ",
                NS_MINBASE, NS_MAXBASE );
        b1 = NS_chiedi_numero( NS_MINBASE, NS_MAXBASE, 10 );

        printf( "Immetti la base di numerazione di destinazione (%d-%d): ",
                NS_MINBASE, NS_MAXBASE );
        b2 = NS_chiedi_numero( NS_MINBASE, NS_MAXBASE, 10 );

        printf( "Immetti il numero da convertire: " );
        n = NS_chiedi_numero( NS_MINVAL, NS_MAXVAL, b1 );

        printf( "\n    base %2d: %s\n", b1, NS_ns(n,buff,b1) );
        printf( "    base %2d: %s\n\n", b2, NS_ns(n,buff,b2) );

        printf( "Vuoi effettuare un'altra conversione? "
                "(\"s\" per continuare) " );

        fgets( buff, NS_DIMBUFFNUM, stdin );
        ripeti = tolower(*buff) != 'n';

        /* se necessario, "svuota" stdin */
        while( buff[strlen(buff)-1] != '\n' )
            fgets( buff, NS_DIMBUFFNUM, stdin );

        printf( "\n\n" );
    } while( ripeti );

    return 0;
}
' ) ++p; if( *p != 'Ciao a te che leggi.

Oggi non sapevo che fare e ho messo insieme una paginata di roba in previsione di un futuro ed ipotetico uso personale. Probabilmente si tratta della classica "reinvenzione della ruota", però sapete che son fatto così e che mi diverto a scrivere 'ste cose. Non escludo che si tratti pure di un modo improprio di ottenere il risultato.

Detto questo... potrebbe essere utile aggiungere questi file alla sezione "esempi" dei programmi presenti su Pierotofy? Se sì, aggiungo; se no, tengo per me. Graditi opinioni e, se non significano "rivoluzionare" tutto (non ne vale la pena, credo), suggerimenti su come migliorare il codice. Meno gradito, ma comunque accettato, un eventuale "ma piantala lì!".

Tre file. Il primo: numeri_e_stringhe.h

/**=============================================================================
                               NUMERI E STRINGHE
                               v1.0 - aprile 2017

Gestisce valori compresi tra 9223372036854775807 e -9223372036854775807 (interi
a 64 bit) con base compresa tra 2 e 36.
=============================================================================**/

#ifndef NUMERI_E_STRINGHE_H_INCLUDED
#define NUMERI_E_STRINGHE_H_INCLUDED

/** ===> INCLUSIONI <========================================================**/

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>  /* per usare i tipi uint64_t, int64_t, int16_t e int8_t */
#include <stdbool.h> /* per usare il tipo bool */
#include <ctype.h>   /* per usare tolower() e toupper() */

/** ===> MACRO <============================================================ **/

#define NS_USACHIEDINUMERO    /* da definire per usare NS_chiedi_numero() */
#define NS_CIFRANONVALIDA  -1 /* restituito come errore da NS_cifra() */
#define NS_MINBASE          2 /* la base non puo' essere inferiore */
#define NS_MAXBASE         36 /* la base non puo' essere superiore */
#define NS_MINVAL          -9223372036854775807LL
#define NS_MAXVAL           9223372036854775807LL
#define NS_DIMBUFFNUM      68 /* le dimensioni del buffer per la
                                 rappresentazione dei numeri a 64 bit
                                 sotto forma di stringa */

/** ===> PROTOTIPI DELLE FUNZIONI <========================================= **/

#ifdef NS_USACHIEDINUMERO
int64_t NS_chiedi_numero( int64_t minimo, int64_t massimo, int8_t base );
#endif // NS_USACHIEDINUMERO

int64_t NS_sn( const char *s, int16_t *qCifre, int8_t base );
char *NS_ns( int64_t n, char *buff, int8_t base );
int8_t NS_cifra( char c, int8_t base );
void NS_usa_cifre_maiuscole( bool usa_cifre_maiuscole );

#endif /* NUMERI_E_STRINGHE_H_INCLUDED */


Il secondo: numeri_e_stringhe.c

/**=============================================================================
                               NUMERI E STRINGHE
                               v1.0 - aprile 2017

Gestisce valori compresi tra 9223372036854775807 e -9223372036854775807 (interi
a 64 bit) con base compresa tra 2 e 36.
=============================================================================**/

#include "numeri_e_stringhe.h"

/** ===> COSTANTI <========================================================= **/

static const char *NS_Cifre = "0123456789abcdefghijklmnopqrstuvwxyz";
static const char NS_SegnoNegativo = '-';
static const char *NS_StrErrBaseNonValida = "(la base eccede i limiti)";

/** ===> VARIABILI GLOBALI PER QUESTO FILE <================================ **/

bool NS_usa_maiuscole = false;

/** ===> DEFINIZIONE DELLE FUNZIONI <======================================= **/

/*==============================================================================
Chiede l'immissione in console di un numero intero compreso tra min e max, dove
min non puo' essere inferiore a NS_MINVAL e max non puo' essere superiore a
NS_MAXVAL. Restituisce il numero immesso come valore di ritorno di tipo int64_t.
La funzione insiste nella sua richiesta fintanto che non viene immesso un dato
accettabile, quindi ritorna.
Per usare questa funzione occorre che sia definita la macro NS_USACHIEDINUMERO.
==============================================================================*/

#ifdef NS_USACHIEDINUMERO
int64_t NS_chiedi_numero( int64_t min, int64_t max, int8_t base ) {
    char buff[NS_DIMBUFFNUM]; /* 64 cifre + il segno negativo */
    bool ripeti, pp = true; /* pp = primo passaggio */
    int16_t l, qCifre;
    int64_t n;

    do {
        if( !pp ) /* se non e' il primo passaggio... */
            printf( "Input non valido, riprova: " );
        else pp = false; /* se e' il primo passaggio */

        fgets( buff, NS_DIMBUFFNUM, stdin ); /* riceviamo l'input */
        for( l=0; buff[l]; ++l ); /* la lunghezza dell'input */

        if( buff[l-1] == '\n' ) {
            n = NS_sn( buff, &qCifre, base ); /* converte in int64_t */
            ripeti = n<min || n>max || qCifre==0;
        }
        else {
            /* se l'ultimo carattere non e' '\n' significa che
               l'input e' stato troncato, il che non va bene;
               eliminiamo i caratteri ancora "pendenti" */
            while( getchar() != '\n' );
            ripeti = true; /* la condizione per ripetere */
        }
    } while( ripeti );

    return n; /* restituisce il numero immesso */
}
#endif // NS_USACHIEDINUMERO

/*==============================================================================
Converte una stringa nel numero intero corrispondente, secondo la base di
numerazione specificata.
Se la stringa inizia con caratteri non idonei a rappresentare le cifre del
sistema di numerazione specificato, quei caratteri non vengono considerati.
Se la stringa contiene una rappresentazione numerica valida, la funzione
restituisce il valore ricavato dalla stringa (in formato int64_t) e immette la
quantita' delle cifre riconosciute all'indirizzo indicato dal parametro qCifre.
Se la stringa NON contiene una rappresentazione numerica valida, la funzione
restituisce 0 e immette 0 anche all'indirizzo indicato dal parametro qCifre.
Se il parametro qCifre e' un puntatore NULL, la funzione non puo' fornire
informazioni circa la quantita' di cifre riconosciute, rendendo di fatto
impossibile al chiamante sapere se la conversione e' stata portata a termine
correttamente oppure no.
==============================================================================*/

int64_t NS_sn( const char *s, int16_t *qCifre, int8_t base ) {
    int16_t totCifre = 0; /* si presuppone il fallimento */
    int64_t r = 0; /* il risultato dell'operazione */

    /* se i parametri sono accettabili, analizziamo la stringa */
    if( s != NULL && (base>=NS_MINBASE&&base<=NS_MAXBASE) ) {
        const char *p = s; /* puntatore ausiliario */
        bool negativo;

        /* scartiamo tutti i caratteri non numerici iniziali */
        while( !(NS_cifra(*p,base)>=0||*p==NS_SegnoNegativo) && *p!='{parsed_message}' ) ++p;

        if( *p != '{parsed_message}' ) { /* se sono rimasti caratteri */
            int16_t i, j; /* contatori */

            if( (negativo=*p==NS_SegnoNegativo) ) ++p; /* saltiamo il segno */
            while( *p == '0' ) ++p; /* saltiamo gli zeri iniziali */

            while( NS_cifra(p[totCifre],base) >= 0 ) /* contiamo le cifre */
                ++totCifre;

            if( totCifre > 0 ) { /* se ci sono cifre valide, calcoliamo */
                for( i=totCifre; i>0; --i ) { /* partendo dal fondo */
                    int64_t tmp=1;
                    for( j=0; j<totCifre-i; ++j ) tmp *= base; /* potenza */
                    r += NS_cifra(p[i-1],base) * tmp;
                }

                if( negativo ) r = -r; /* se era negativo, ripristiniamo */
            }
        }
    }

    if( qCifre != NULL ) *qCifre = totCifre; /* solo se non e' NULL */

    return r;
}

/*==============================================================================
Converte un numero intero in formato int64_t nella sua rappresentazione in forma
di stringa, secondo la base di numerazione specificata.
Se il parametro buff e' un puntatore valido, la funzione impiega lo spazio di
memoria puntato per collocarvi la stringa risultante dalla conversione. Spetta
al chiamante assicurarsi che buff punti a uno spazio di memoria sufficiente per
contenere la stringa (il caso piu' "esigente" riguarda il valore a 64 bit
massimo in formato binario: 64 caratteri piu' il terminatore, eventualmente con
l'aggiunta d'un segno negativo -- 66 caratteri in tutto).
Se il parametro buff e' NULL, la funzione inserisce la stringa risultante in un
buffer statico costituito da NS_DIMBUFFNUM char. Ovviamente, ogni nuova chiamata
alla funzione sovrascrive il buffer cancellando l'esito delle eventuali
conversioni precedenti.
La funzione fallisce (restituendo una stringa che descrive l'errore) solo se
il parametro base eccede i limiti consentiti da NS_MINBASE e NS_MAXBASE.
==============================================================================*/

char *NS_ns( int64_t n, char *buff, int8_t base ) {
    static char sBuff[NS_DIMBUFFNUM]; /* max 64 cifre + il segno negativo */
    uint64_t un; /* necessario per il valore negativo minimo */
    int16_t i; /* deve poter contenere almeno la lunghezza della stringa */

    /* se il parametro buff e' nullo, usiamo il buffer statico */
    if( buff == NULL ) buff = sBuff;

    if( base>=NS_MINBASE && base<=NS_MAXBASE ) {
        int16_t l, lMezzi;
        bool negativo;
        int8_t cifra;

        negativo = n < 0; /* memorizziamo il segno */
        un = negativo ? -n : n; /* usiamo sempre un valore positivo */

        /* N.B. la stringa viene generata "all'indietro" */
        for( l=0; un!=0; ++l ) {
            cifra = un%base;
            buff[l] = NS_Cifre[cifra];
            un /= base;
        }

        if( negativo ) buff[l++] = NS_SegnoNegativo; /* apponiamo il segno? */
        buff[l] = '{parsed_message}'; /* terminiamo la stringa */

        /* "rovesciamo" la stringa (generata all'indietro) */
        for( lMezzi=l/2, i=0; i<lMezzi; ++i ) {
            char aux = buff[i];
            buff[i] = buff[l-i-1];
            buff[l-i-1] = aux;
        }

        /* se necessario, usiamo le cifre in caratteri maiuscoli */
        if( NS_usa_maiuscole )
            for( i=0; i<l; ++i )
                buff[i] = toupper( buff[i] );
    }
    else { /* la base eccede i limiti imposti da NS_MINBASE e NS_MAXBASE */
        for( i=0; NS_StrErrBaseNonValida[i]; ++i )
            buff[i] = NS_StrErrBaseNonValida[i]; /* copiamo l'errore */
        buff[i] = '{parsed_message}'; /* terminiamo la stringa */
    }

    return buff; /* restituiamo un puntatore al buffer effettivamente usato */
}

/*==============================================================================
Verifica se c corrisponde a una delle cifre valide nel sistema di numerazione
che impiega la base specificata dal parametro base. Se c e' una cifra valida
restituisce il valore della cifra; se c NON e' una cifra valida restituisce
NS_CIFRANONVALIDA.
==============================================================================*/

int8_t NS_cifra( char c, int8_t base ) {
    c = tolower(c);
    int8_t i;

    if( base>=NS_MINBASE && base<=NS_MAXBASE )
        for( i=0; i<base; ++i )
            if( c == NS_Cifre[i] )
                return i;
    return NS_CIFRANONVALIDA;
}

/*==============================================================================
Imposta una variabile statica che fa si' che le altre funzioni impieghino (nelle
chiamate successive) caratteri maiuscoli o minuscoli come cifre per quei sistemi
di numerazione che richiedono l'uso di oltre 10 cifre.
==============================================================================*/

void NS_usa_cifre_maiuscole( bool usa_cifre_maiuscole ) {
    NS_usa_maiuscole = usa_cifre_maiuscole;
}


Il terzo, con un programmino d'esempio d'uso: main.c

/**=============================================================================
Programma d'esempio per numeri_e_stringhe.
=============================================================================**/

#include <string.h>
#include "numeri_e_stringhe.h"

int main() {
    char buff[NS_DIMBUFFNUM];
    int8_t b1, b2;
    int64_t n;
    bool ripeti;

    printf( "CONVERTE LA BASE DI NUMERAZIONE DI UN NUMERO DATO\n" );
    printf( "=================================================\n\n" );

    do {
        printf( "Immetti la base di numerazione iniziale (%d-%d): ",
                NS_MINBASE, NS_MAXBASE );
        b1 = NS_chiedi_numero( NS_MINBASE, NS_MAXBASE, 10 );

        printf( "Immetti la base di numerazione di destinazione (%d-%d): ",
                NS_MINBASE, NS_MAXBASE );
        b2 = NS_chiedi_numero( NS_MINBASE, NS_MAXBASE, 10 );

        printf( "Immetti il numero da convertire: " );
        n = NS_chiedi_numero( NS_MINVAL, NS_MAXVAL, b1 );

        printf( "\n    base %2d: %s\n", b1, NS_ns(n,buff,b1) );
        printf( "    base %2d: %s\n\n", b2, NS_ns(n,buff,b2) );

        printf( "Vuoi effettuare un'altra conversione? "
                "(\"s\" per continuare) " );

        fgets( buff, NS_DIMBUFFNUM, stdin );
        ripeti = tolower(*buff) != 'n';

        /* se necessario, "svuota" stdin */
        while( buff[strlen(buff)-1] != '\n' )
            fgets( buff, NS_DIMBUFFNUM, stdin );

        printf( "\n\n" );
    } while( ripeti );

    return 0;
}
' ) { /* se sono rimasti caratteri */ int16_t i, j; /* contatori */ if( (negativo=*p==NS_SegnoNegativo) ) ++p; /* saltiamo il segno */ while( *p == '0' ) ++p; /* saltiamo gli zeri iniziali */ while( NS_cifra(p[totCifre],base) >= 0 ) /* contiamo le cifre */ ++totCifre; if( totCifre > 0 ) { /* se ci sono cifre valide, calcoliamo */ for( i=totCifre; i>0; --i ) { /* partendo dal fondo */ int64_t tmp=1; for( j=0; j<totCifre-i; ++j ) tmp *= base; /* potenza */ r += NS_cifra(p[i-1],base) * tmp; } if( negativo ) r = -r; /* se era negativo, ripristiniamo */ } } } if( qCifre != NULL ) *qCifre = totCifre; /* solo se non e' NULL */ return r; } /*============================================================================== Converte un numero intero in formato int64_t nella sua rappresentazione in forma di stringa, secondo la base di numerazione specificata. Se il parametro buff e' un puntatore valido, la funzione impiega lo spazio di memoria puntato per collocarvi la stringa risultante dalla conversione. Spetta al chiamante assicurarsi che buff punti a uno spazio di memoria sufficiente per contenere la stringa (il caso piu' "esigente" riguarda il valore a 64 bit massimo in formato binario: 64 caratteri piu' il terminatore, eventualmente con l'aggiunta d'un segno negativo -- 66 caratteri in tutto). Se il parametro buff e' NULL, la funzione inserisce la stringa risultante in un buffer statico costituito da NS_DIMBUFFNUM char. Ovviamente, ogni nuova chiamata alla funzione sovrascrive il buffer cancellando l'esito delle eventuali conversioni precedenti. La funzione fallisce (restituendo una stringa che descrive l'errore) solo se il parametro base eccede i limiti consentiti da NS_MINBASE e NS_MAXBASE. ==============================================================================*/ char *NS_ns( int64_t n, char *buff, int8_t base ) { static char sBuff[NS_DIMBUFFNUM]; /* max 64 cifre + il segno negativo */ uint64_t un; /* necessario per il valore negativo minimo */ int16_t i; /* deve poter contenere almeno la lunghezza della stringa */ /* se il parametro buff e' nullo, usiamo il buffer statico */ if( buff == NULL ) buff = sBuff; if( base>=NS_MINBASE && base<=NS_MAXBASE ) { int16_t l, lMezzi; bool negativo; int8_t cifra; negativo = n < 0; /* memorizziamo il segno */ un = negativo ? -n : n; /* usiamo sempre un valore positivo */ /* N.B. la stringa viene generata "all'indietro" */ for( l=0; un!=0; ++l ) { cifra = un%base; buff[l] = NS_Cifre[cifra]; un /= base; } if( negativo ) buff[l++] = NS_SegnoNegativo; /* apponiamo il segno? */ buff[l] = 'Ciao a te che leggi.

Oggi non sapevo che fare e ho messo insieme una paginata di roba in previsione di un futuro ed ipotetico uso personale. Probabilmente si tratta della classica "reinvenzione della ruota", però sapete che son fatto così e che mi diverto a scrivere 'ste cose. Non escludo che si tratti pure di un modo improprio di ottenere il risultato.

Detto questo... potrebbe essere utile aggiungere questi file alla sezione "esempi" dei programmi presenti su Pierotofy? Se sì, aggiungo; se no, tengo per me. Graditi opinioni e, se non significano "rivoluzionare" tutto (non ne vale la pena, credo), suggerimenti su come migliorare il codice. Meno gradito, ma comunque accettato, un eventuale "ma piantala lì!".

Tre file. Il primo: numeri_e_stringhe.h

/**=============================================================================
                               NUMERI E STRINGHE
                               v1.0 - aprile 2017

Gestisce valori compresi tra 9223372036854775807 e -9223372036854775807 (interi
a 64 bit) con base compresa tra 2 e 36.
=============================================================================**/

#ifndef NUMERI_E_STRINGHE_H_INCLUDED
#define NUMERI_E_STRINGHE_H_INCLUDED

/** ===> INCLUSIONI <========================================================**/

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>  /* per usare i tipi uint64_t, int64_t, int16_t e int8_t */
#include <stdbool.h> /* per usare il tipo bool */
#include <ctype.h>   /* per usare tolower() e toupper() */

/** ===> MACRO <============================================================ **/

#define NS_USACHIEDINUMERO    /* da definire per usare NS_chiedi_numero() */
#define NS_CIFRANONVALIDA  -1 /* restituito come errore da NS_cifra() */
#define NS_MINBASE          2 /* la base non puo' essere inferiore */
#define NS_MAXBASE         36 /* la base non puo' essere superiore */
#define NS_MINVAL          -9223372036854775807LL
#define NS_MAXVAL           9223372036854775807LL
#define NS_DIMBUFFNUM      68 /* le dimensioni del buffer per la
                                 rappresentazione dei numeri a 64 bit
                                 sotto forma di stringa */

/** ===> PROTOTIPI DELLE FUNZIONI <========================================= **/

#ifdef NS_USACHIEDINUMERO
int64_t NS_chiedi_numero( int64_t minimo, int64_t massimo, int8_t base );
#endif // NS_USACHIEDINUMERO

int64_t NS_sn( const char *s, int16_t *qCifre, int8_t base );
char *NS_ns( int64_t n, char *buff, int8_t base );
int8_t NS_cifra( char c, int8_t base );
void NS_usa_cifre_maiuscole( bool usa_cifre_maiuscole );

#endif /* NUMERI_E_STRINGHE_H_INCLUDED */


Il secondo: numeri_e_stringhe.c

/**=============================================================================
                               NUMERI E STRINGHE
                               v1.0 - aprile 2017

Gestisce valori compresi tra 9223372036854775807 e -9223372036854775807 (interi
a 64 bit) con base compresa tra 2 e 36.
=============================================================================**/

#include "numeri_e_stringhe.h"

/** ===> COSTANTI <========================================================= **/

static const char *NS_Cifre = "0123456789abcdefghijklmnopqrstuvwxyz";
static const char NS_SegnoNegativo = '-';
static const char *NS_StrErrBaseNonValida = "(la base eccede i limiti)";

/** ===> VARIABILI GLOBALI PER QUESTO FILE <================================ **/

bool NS_usa_maiuscole = false;

/** ===> DEFINIZIONE DELLE FUNZIONI <======================================= **/

/*==============================================================================
Chiede l'immissione in console di un numero intero compreso tra min e max, dove
min non puo' essere inferiore a NS_MINVAL e max non puo' essere superiore a
NS_MAXVAL. Restituisce il numero immesso come valore di ritorno di tipo int64_t.
La funzione insiste nella sua richiesta fintanto che non viene immesso un dato
accettabile, quindi ritorna.
Per usare questa funzione occorre che sia definita la macro NS_USACHIEDINUMERO.
==============================================================================*/

#ifdef NS_USACHIEDINUMERO
int64_t NS_chiedi_numero( int64_t min, int64_t max, int8_t base ) {
    char buff[NS_DIMBUFFNUM]; /* 64 cifre + il segno negativo */
    bool ripeti, pp = true; /* pp = primo passaggio */
    int16_t l, qCifre;
    int64_t n;

    do {
        if( !pp ) /* se non e' il primo passaggio... */
            printf( "Input non valido, riprova: " );
        else pp = false; /* se e' il primo passaggio */

        fgets( buff, NS_DIMBUFFNUM, stdin ); /* riceviamo l'input */
        for( l=0; buff[l]; ++l ); /* la lunghezza dell'input */

        if( buff[l-1] == '\n' ) {
            n = NS_sn( buff, &qCifre, base ); /* converte in int64_t */
            ripeti = n<min || n>max || qCifre==0;
        }
        else {
            /* se l'ultimo carattere non e' '\n' significa che
               l'input e' stato troncato, il che non va bene;
               eliminiamo i caratteri ancora "pendenti" */
            while( getchar() != '\n' );
            ripeti = true; /* la condizione per ripetere */
        }
    } while( ripeti );

    return n; /* restituisce il numero immesso */
}
#endif // NS_USACHIEDINUMERO

/*==============================================================================
Converte una stringa nel numero intero corrispondente, secondo la base di
numerazione specificata.
Se la stringa inizia con caratteri non idonei a rappresentare le cifre del
sistema di numerazione specificato, quei caratteri non vengono considerati.
Se la stringa contiene una rappresentazione numerica valida, la funzione
restituisce il valore ricavato dalla stringa (in formato int64_t) e immette la
quantita' delle cifre riconosciute all'indirizzo indicato dal parametro qCifre.
Se la stringa NON contiene una rappresentazione numerica valida, la funzione
restituisce 0 e immette 0 anche all'indirizzo indicato dal parametro qCifre.
Se il parametro qCifre e' un puntatore NULL, la funzione non puo' fornire
informazioni circa la quantita' di cifre riconosciute, rendendo di fatto
impossibile al chiamante sapere se la conversione e' stata portata a termine
correttamente oppure no.
==============================================================================*/

int64_t NS_sn( const char *s, int16_t *qCifre, int8_t base ) {
    int16_t totCifre = 0; /* si presuppone il fallimento */
    int64_t r = 0; /* il risultato dell'operazione */

    /* se i parametri sono accettabili, analizziamo la stringa */
    if( s != NULL && (base>=NS_MINBASE&&base<=NS_MAXBASE) ) {
        const char *p = s; /* puntatore ausiliario */
        bool negativo;

        /* scartiamo tutti i caratteri non numerici iniziali */
        while( !(NS_cifra(*p,base)>=0||*p==NS_SegnoNegativo) && *p!='{parsed_message}' ) ++p;

        if( *p != '{parsed_message}' ) { /* se sono rimasti caratteri */
            int16_t i, j; /* contatori */

            if( (negativo=*p==NS_SegnoNegativo) ) ++p; /* saltiamo il segno */
            while( *p == '0' ) ++p; /* saltiamo gli zeri iniziali */

            while( NS_cifra(p[totCifre],base) >= 0 ) /* contiamo le cifre */
                ++totCifre;

            if( totCifre > 0 ) { /* se ci sono cifre valide, calcoliamo */
                for( i=totCifre; i>0; --i ) { /* partendo dal fondo */
                    int64_t tmp=1;
                    for( j=0; j<totCifre-i; ++j ) tmp *= base; /* potenza */
                    r += NS_cifra(p[i-1],base) * tmp;
                }

                if( negativo ) r = -r; /* se era negativo, ripristiniamo */
            }
        }
    }

    if( qCifre != NULL ) *qCifre = totCifre; /* solo se non e' NULL */

    return r;
}

/*==============================================================================
Converte un numero intero in formato int64_t nella sua rappresentazione in forma
di stringa, secondo la base di numerazione specificata.
Se il parametro buff e' un puntatore valido, la funzione impiega lo spazio di
memoria puntato per collocarvi la stringa risultante dalla conversione. Spetta
al chiamante assicurarsi che buff punti a uno spazio di memoria sufficiente per
contenere la stringa (il caso piu' "esigente" riguarda il valore a 64 bit
massimo in formato binario: 64 caratteri piu' il terminatore, eventualmente con
l'aggiunta d'un segno negativo -- 66 caratteri in tutto).
Se il parametro buff e' NULL, la funzione inserisce la stringa risultante in un
buffer statico costituito da NS_DIMBUFFNUM char. Ovviamente, ogni nuova chiamata
alla funzione sovrascrive il buffer cancellando l'esito delle eventuali
conversioni precedenti.
La funzione fallisce (restituendo una stringa che descrive l'errore) solo se
il parametro base eccede i limiti consentiti da NS_MINBASE e NS_MAXBASE.
==============================================================================*/

char *NS_ns( int64_t n, char *buff, int8_t base ) {
    static char sBuff[NS_DIMBUFFNUM]; /* max 64 cifre + il segno negativo */
    uint64_t un; /* necessario per il valore negativo minimo */
    int16_t i; /* deve poter contenere almeno la lunghezza della stringa */

    /* se il parametro buff e' nullo, usiamo il buffer statico */
    if( buff == NULL ) buff = sBuff;

    if( base>=NS_MINBASE && base<=NS_MAXBASE ) {
        int16_t l, lMezzi;
        bool negativo;
        int8_t cifra;

        negativo = n < 0; /* memorizziamo il segno */
        un = negativo ? -n : n; /* usiamo sempre un valore positivo */

        /* N.B. la stringa viene generata "all'indietro" */
        for( l=0; un!=0; ++l ) {
            cifra = un%base;
            buff[l] = NS_Cifre[cifra];
            un /= base;
        }

        if( negativo ) buff[l++] = NS_SegnoNegativo; /* apponiamo il segno? */
        buff[l] = '{parsed_message}'; /* terminiamo la stringa */

        /* "rovesciamo" la stringa (generata all'indietro) */
        for( lMezzi=l/2, i=0; i<lMezzi; ++i ) {
            char aux = buff[i];
            buff[i] = buff[l-i-1];
            buff[l-i-1] = aux;
        }

        /* se necessario, usiamo le cifre in caratteri maiuscoli */
        if( NS_usa_maiuscole )
            for( i=0; i<l; ++i )
                buff[i] = toupper( buff[i] );
    }
    else { /* la base eccede i limiti imposti da NS_MINBASE e NS_MAXBASE */
        for( i=0; NS_StrErrBaseNonValida[i]; ++i )
            buff[i] = NS_StrErrBaseNonValida[i]; /* copiamo l'errore */
        buff[i] = '{parsed_message}'; /* terminiamo la stringa */
    }

    return buff; /* restituiamo un puntatore al buffer effettivamente usato */
}

/*==============================================================================
Verifica se c corrisponde a una delle cifre valide nel sistema di numerazione
che impiega la base specificata dal parametro base. Se c e' una cifra valida
restituisce il valore della cifra; se c NON e' una cifra valida restituisce
NS_CIFRANONVALIDA.
==============================================================================*/

int8_t NS_cifra( char c, int8_t base ) {
    c = tolower(c);
    int8_t i;

    if( base>=NS_MINBASE && base<=NS_MAXBASE )
        for( i=0; i<base; ++i )
            if( c == NS_Cifre[i] )
                return i;
    return NS_CIFRANONVALIDA;
}

/*==============================================================================
Imposta una variabile statica che fa si' che le altre funzioni impieghino (nelle
chiamate successive) caratteri maiuscoli o minuscoli come cifre per quei sistemi
di numerazione che richiedono l'uso di oltre 10 cifre.
==============================================================================*/

void NS_usa_cifre_maiuscole( bool usa_cifre_maiuscole ) {
    NS_usa_maiuscole = usa_cifre_maiuscole;
}


Il terzo, con un programmino d'esempio d'uso: main.c

/**=============================================================================
Programma d'esempio per numeri_e_stringhe.
=============================================================================**/

#include <string.h>
#include "numeri_e_stringhe.h"

int main() {
    char buff[NS_DIMBUFFNUM];
    int8_t b1, b2;
    int64_t n;
    bool ripeti;

    printf( "CONVERTE LA BASE DI NUMERAZIONE DI UN NUMERO DATO\n" );
    printf( "=================================================\n\n" );

    do {
        printf( "Immetti la base di numerazione iniziale (%d-%d): ",
                NS_MINBASE, NS_MAXBASE );
        b1 = NS_chiedi_numero( NS_MINBASE, NS_MAXBASE, 10 );

        printf( "Immetti la base di numerazione di destinazione (%d-%d): ",
                NS_MINBASE, NS_MAXBASE );
        b2 = NS_chiedi_numero( NS_MINBASE, NS_MAXBASE, 10 );

        printf( "Immetti il numero da convertire: " );
        n = NS_chiedi_numero( NS_MINVAL, NS_MAXVAL, b1 );

        printf( "\n    base %2d: %s\n", b1, NS_ns(n,buff,b1) );
        printf( "    base %2d: %s\n\n", b2, NS_ns(n,buff,b2) );

        printf( "Vuoi effettuare un'altra conversione? "
                "(\"s\" per continuare) " );

        fgets( buff, NS_DIMBUFFNUM, stdin );
        ripeti = tolower(*buff) != 'n';

        /* se necessario, "svuota" stdin */
        while( buff[strlen(buff)-1] != '\n' )
            fgets( buff, NS_DIMBUFFNUM, stdin );

        printf( "\n\n" );
    } while( ripeti );

    return 0;
}
'; /* terminiamo la stringa */ /* "rovesciamo" la stringa (generata all'indietro) */ for( lMezzi=l/2, i=0; i<lMezzi; ++i ) { char aux = buff[i]; buff[i] = buff[l-i-1]; buff[l-i-1] = aux; } /* se necessario, usiamo le cifre in caratteri maiuscoli */ if( NS_usa_maiuscole ) for( i=0; i<l; ++i ) buff[i] = toupper( buff[i] ); } else { /* la base eccede i limiti imposti da NS_MINBASE e NS_MAXBASE */ for( i=0; NS_StrErrBaseNonValida[i]; ++i ) buff[i] = NS_StrErrBaseNonValida[i]; /* copiamo l'errore */ buff[i] = 'Ciao a te che leggi.

Oggi non sapevo che fare e ho messo insieme una paginata di roba in previsione di un futuro ed ipotetico uso personale. Probabilmente si tratta della classica "reinvenzione della ruota", però sapete che son fatto così e che mi diverto a scrivere 'ste cose. Non escludo che si tratti pure di un modo improprio di ottenere il risultato.

Detto questo... potrebbe essere utile aggiungere questi file alla sezione "esempi" dei programmi presenti su Pierotofy? Se sì, aggiungo; se no, tengo per me. Graditi opinioni e, se non significano "rivoluzionare" tutto (non ne vale la pena, credo), suggerimenti su come migliorare il codice. Meno gradito, ma comunque accettato, un eventuale "ma piantala lì!".

Tre file. Il primo: numeri_e_stringhe.h

/**=============================================================================
                               NUMERI E STRINGHE
                               v1.0 - aprile 2017

Gestisce valori compresi tra 9223372036854775807 e -9223372036854775807 (interi
a 64 bit) con base compresa tra 2 e 36.
=============================================================================**/

#ifndef NUMERI_E_STRINGHE_H_INCLUDED
#define NUMERI_E_STRINGHE_H_INCLUDED

/** ===> INCLUSIONI <========================================================**/

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>  /* per usare i tipi uint64_t, int64_t, int16_t e int8_t */
#include <stdbool.h> /* per usare il tipo bool */
#include <ctype.h>   /* per usare tolower() e toupper() */

/** ===> MACRO <============================================================ **/

#define NS_USACHIEDINUMERO    /* da definire per usare NS_chiedi_numero() */
#define NS_CIFRANONVALIDA  -1 /* restituito come errore da NS_cifra() */
#define NS_MINBASE          2 /* la base non puo' essere inferiore */
#define NS_MAXBASE         36 /* la base non puo' essere superiore */
#define NS_MINVAL          -9223372036854775807LL
#define NS_MAXVAL           9223372036854775807LL
#define NS_DIMBUFFNUM      68 /* le dimensioni del buffer per la
                                 rappresentazione dei numeri a 64 bit
                                 sotto forma di stringa */

/** ===> PROTOTIPI DELLE FUNZIONI <========================================= **/

#ifdef NS_USACHIEDINUMERO
int64_t NS_chiedi_numero( int64_t minimo, int64_t massimo, int8_t base );
#endif // NS_USACHIEDINUMERO

int64_t NS_sn( const char *s, int16_t *qCifre, int8_t base );
char *NS_ns( int64_t n, char *buff, int8_t base );
int8_t NS_cifra( char c, int8_t base );
void NS_usa_cifre_maiuscole( bool usa_cifre_maiuscole );

#endif /* NUMERI_E_STRINGHE_H_INCLUDED */


Il secondo: numeri_e_stringhe.c

/**=============================================================================
                               NUMERI E STRINGHE
                               v1.0 - aprile 2017

Gestisce valori compresi tra 9223372036854775807 e -9223372036854775807 (interi
a 64 bit) con base compresa tra 2 e 36.
=============================================================================**/

#include "numeri_e_stringhe.h"

/** ===> COSTANTI <========================================================= **/

static const char *NS_Cifre = "0123456789abcdefghijklmnopqrstuvwxyz";
static const char NS_SegnoNegativo = '-';
static const char *NS_StrErrBaseNonValida = "(la base eccede i limiti)";

/** ===> VARIABILI GLOBALI PER QUESTO FILE <================================ **/

bool NS_usa_maiuscole = false;

/** ===> DEFINIZIONE DELLE FUNZIONI <======================================= **/

/*==============================================================================
Chiede l'immissione in console di un numero intero compreso tra min e max, dove
min non puo' essere inferiore a NS_MINVAL e max non puo' essere superiore a
NS_MAXVAL. Restituisce il numero immesso come valore di ritorno di tipo int64_t.
La funzione insiste nella sua richiesta fintanto che non viene immesso un dato
accettabile, quindi ritorna.
Per usare questa funzione occorre che sia definita la macro NS_USACHIEDINUMERO.
==============================================================================*/

#ifdef NS_USACHIEDINUMERO
int64_t NS_chiedi_numero( int64_t min, int64_t max, int8_t base ) {
    char buff[NS_DIMBUFFNUM]; /* 64 cifre + il segno negativo */
    bool ripeti, pp = true; /* pp = primo passaggio */
    int16_t l, qCifre;
    int64_t n;

    do {
        if( !pp ) /* se non e' il primo passaggio... */
            printf( "Input non valido, riprova: " );
        else pp = false; /* se e' il primo passaggio */

        fgets( buff, NS_DIMBUFFNUM, stdin ); /* riceviamo l'input */
        for( l=0; buff[l]; ++l ); /* la lunghezza dell'input */

        if( buff[l-1] == '\n' ) {
            n = NS_sn( buff, &qCifre, base ); /* converte in int64_t */
            ripeti = n<min || n>max || qCifre==0;
        }
        else {
            /* se l'ultimo carattere non e' '\n' significa che
               l'input e' stato troncato, il che non va bene;
               eliminiamo i caratteri ancora "pendenti" */
            while( getchar() != '\n' );
            ripeti = true; /* la condizione per ripetere */
        }
    } while( ripeti );

    return n; /* restituisce il numero immesso */
}
#endif // NS_USACHIEDINUMERO

/*==============================================================================
Converte una stringa nel numero intero corrispondente, secondo la base di
numerazione specificata.
Se la stringa inizia con caratteri non idonei a rappresentare le cifre del
sistema di numerazione specificato, quei caratteri non vengono considerati.
Se la stringa contiene una rappresentazione numerica valida, la funzione
restituisce il valore ricavato dalla stringa (in formato int64_t) e immette la
quantita' delle cifre riconosciute all'indirizzo indicato dal parametro qCifre.
Se la stringa NON contiene una rappresentazione numerica valida, la funzione
restituisce 0 e immette 0 anche all'indirizzo indicato dal parametro qCifre.
Se il parametro qCifre e' un puntatore NULL, la funzione non puo' fornire
informazioni circa la quantita' di cifre riconosciute, rendendo di fatto
impossibile al chiamante sapere se la conversione e' stata portata a termine
correttamente oppure no.
==============================================================================*/

int64_t NS_sn( const char *s, int16_t *qCifre, int8_t base ) {
    int16_t totCifre = 0; /* si presuppone il fallimento */
    int64_t r = 0; /* il risultato dell'operazione */

    /* se i parametri sono accettabili, analizziamo la stringa */
    if( s != NULL && (base>=NS_MINBASE&&base<=NS_MAXBASE) ) {
        const char *p = s; /* puntatore ausiliario */
        bool negativo;

        /* scartiamo tutti i caratteri non numerici iniziali */
        while( !(NS_cifra(*p,base)>=0||*p==NS_SegnoNegativo) && *p!='{parsed_message}' ) ++p;

        if( *p != '{parsed_message}' ) { /* se sono rimasti caratteri */
            int16_t i, j; /* contatori */

            if( (negativo=*p==NS_SegnoNegativo) ) ++p; /* saltiamo il segno */
            while( *p == '0' ) ++p; /* saltiamo gli zeri iniziali */

            while( NS_cifra(p[totCifre],base) >= 0 ) /* contiamo le cifre */
                ++totCifre;

            if( totCifre > 0 ) { /* se ci sono cifre valide, calcoliamo */
                for( i=totCifre; i>0; --i ) { /* partendo dal fondo */
                    int64_t tmp=1;
                    for( j=0; j<totCifre-i; ++j ) tmp *= base; /* potenza */
                    r += NS_cifra(p[i-1],base) * tmp;
                }

                if( negativo ) r = -r; /* se era negativo, ripristiniamo */
            }
        }
    }

    if( qCifre != NULL ) *qCifre = totCifre; /* solo se non e' NULL */

    return r;
}

/*==============================================================================
Converte un numero intero in formato int64_t nella sua rappresentazione in forma
di stringa, secondo la base di numerazione specificata.
Se il parametro buff e' un puntatore valido, la funzione impiega lo spazio di
memoria puntato per collocarvi la stringa risultante dalla conversione. Spetta
al chiamante assicurarsi che buff punti a uno spazio di memoria sufficiente per
contenere la stringa (il caso piu' "esigente" riguarda il valore a 64 bit
massimo in formato binario: 64 caratteri piu' il terminatore, eventualmente con
l'aggiunta d'un segno negativo -- 66 caratteri in tutto).
Se il parametro buff e' NULL, la funzione inserisce la stringa risultante in un
buffer statico costituito da NS_DIMBUFFNUM char. Ovviamente, ogni nuova chiamata
alla funzione sovrascrive il buffer cancellando l'esito delle eventuali
conversioni precedenti.
La funzione fallisce (restituendo una stringa che descrive l'errore) solo se
il parametro base eccede i limiti consentiti da NS_MINBASE e NS_MAXBASE.
==============================================================================*/

char *NS_ns( int64_t n, char *buff, int8_t base ) {
    static char sBuff[NS_DIMBUFFNUM]; /* max 64 cifre + il segno negativo */
    uint64_t un; /* necessario per il valore negativo minimo */
    int16_t i; /* deve poter contenere almeno la lunghezza della stringa */

    /* se il parametro buff e' nullo, usiamo il buffer statico */
    if( buff == NULL ) buff = sBuff;

    if( base>=NS_MINBASE && base<=NS_MAXBASE ) {
        int16_t l, lMezzi;
        bool negativo;
        int8_t cifra;

        negativo = n < 0; /* memorizziamo il segno */
        un = negativo ? -n : n; /* usiamo sempre un valore positivo */

        /* N.B. la stringa viene generata "all'indietro" */
        for( l=0; un!=0; ++l ) {
            cifra = un%base;
            buff[l] = NS_Cifre[cifra];
            un /= base;
        }

        if( negativo ) buff[l++] = NS_SegnoNegativo; /* apponiamo il segno? */
        buff[l] = '{parsed_message}'; /* terminiamo la stringa */

        /* "rovesciamo" la stringa (generata all'indietro) */
        for( lMezzi=l/2, i=0; i<lMezzi; ++i ) {
            char aux = buff[i];
            buff[i] = buff[l-i-1];
            buff[l-i-1] = aux;
        }

        /* se necessario, usiamo le cifre in caratteri maiuscoli */
        if( NS_usa_maiuscole )
            for( i=0; i<l; ++i )
                buff[i] = toupper( buff[i] );
    }
    else { /* la base eccede i limiti imposti da NS_MINBASE e NS_MAXBASE */
        for( i=0; NS_StrErrBaseNonValida[i]; ++i )
            buff[i] = NS_StrErrBaseNonValida[i]; /* copiamo l'errore */
        buff[i] = '{parsed_message}'; /* terminiamo la stringa */
    }

    return buff; /* restituiamo un puntatore al buffer effettivamente usato */
}

/*==============================================================================
Verifica se c corrisponde a una delle cifre valide nel sistema di numerazione
che impiega la base specificata dal parametro base. Se c e' una cifra valida
restituisce il valore della cifra; se c NON e' una cifra valida restituisce
NS_CIFRANONVALIDA.
==============================================================================*/

int8_t NS_cifra( char c, int8_t base ) {
    c = tolower(c);
    int8_t i;

    if( base>=NS_MINBASE && base<=NS_MAXBASE )
        for( i=0; i<base; ++i )
            if( c == NS_Cifre[i] )
                return i;
    return NS_CIFRANONVALIDA;
}

/*==============================================================================
Imposta una variabile statica che fa si' che le altre funzioni impieghino (nelle
chiamate successive) caratteri maiuscoli o minuscoli come cifre per quei sistemi
di numerazione che richiedono l'uso di oltre 10 cifre.
==============================================================================*/

void NS_usa_cifre_maiuscole( bool usa_cifre_maiuscole ) {
    NS_usa_maiuscole = usa_cifre_maiuscole;
}


Il terzo, con un programmino d'esempio d'uso: main.c

/**=============================================================================
Programma d'esempio per numeri_e_stringhe.
=============================================================================**/

#include <string.h>
#include "numeri_e_stringhe.h"

int main() {
    char buff[NS_DIMBUFFNUM];
    int8_t b1, b2;
    int64_t n;
    bool ripeti;

    printf( "CONVERTE LA BASE DI NUMERAZIONE DI UN NUMERO DATO\n" );
    printf( "=================================================\n\n" );

    do {
        printf( "Immetti la base di numerazione iniziale (%d-%d): ",
                NS_MINBASE, NS_MAXBASE );
        b1 = NS_chiedi_numero( NS_MINBASE, NS_MAXBASE, 10 );

        printf( "Immetti la base di numerazione di destinazione (%d-%d): ",
                NS_MINBASE, NS_MAXBASE );
        b2 = NS_chiedi_numero( NS_MINBASE, NS_MAXBASE, 10 );

        printf( "Immetti il numero da convertire: " );
        n = NS_chiedi_numero( NS_MINVAL, NS_MAXVAL, b1 );

        printf( "\n    base %2d: %s\n", b1, NS_ns(n,buff,b1) );
        printf( "    base %2d: %s\n\n", b2, NS_ns(n,buff,b2) );

        printf( "Vuoi effettuare un'altra conversione? "
                "(\"s\" per continuare) " );

        fgets( buff, NS_DIMBUFFNUM, stdin );
        ripeti = tolower(*buff) != 'n';

        /* se necessario, "svuota" stdin */
        while( buff[strlen(buff)-1] != '\n' )
            fgets( buff, NS_DIMBUFFNUM, stdin );

        printf( "\n\n" );
    } while( ripeti );

    return 0;
}
'; /* terminiamo la stringa */ } return buff; /* restituiamo un puntatore al buffer effettivamente usato */ } /*============================================================================== Verifica se c corrisponde a una delle cifre valide nel sistema di numerazione che impiega la base specificata dal parametro base. Se c e' una cifra valida restituisce il valore della cifra; se c NON e' una cifra valida restituisce NS_CIFRANONVALIDA. ==============================================================================*/ int8_t NS_cifra( char c, int8_t base ) { c = tolower(c); int8_t i; if( base>=NS_MINBASE && base<=NS_MAXBASE ) for( i=0; i<base; ++i ) if( c == NS_Cifre[i] ) return i; return NS_CIFRANONVALIDA; } /*============================================================================== Imposta una variabile statica che fa si' che le altre funzioni impieghino (nelle chiamate successive) caratteri maiuscoli o minuscoli come cifre per quei sistemi di numerazione che richiedono l'uso di oltre 10 cifre. ==============================================================================*/ void NS_usa_cifre_maiuscole( bool usa_cifre_maiuscole ) { NS_usa_maiuscole = usa_cifre_maiuscole; }


Il terzo, con un programmino d'esempio d'uso: main.c

/**=============================================================================
Programma d'esempio per numeri_e_stringhe.
=============================================================================**/

#include <string.h>
#include "numeri_e_stringhe.h"

int main() {
    char buff[NS_DIMBUFFNUM];
    int8_t b1, b2;
    int64_t n;
    bool ripeti;

    printf( "CONVERTE LA BASE DI NUMERAZIONE DI UN NUMERO DATO\n" );
    printf( "=================================================\n\n" );

    do {
        printf( "Immetti la base di numerazione iniziale (%d-%d): ",
                NS_MINBASE, NS_MAXBASE );
        b1 = NS_chiedi_numero( NS_MINBASE, NS_MAXBASE, 10 );

        printf( "Immetti la base di numerazione di destinazione (%d-%d): ",
                NS_MINBASE, NS_MAXBASE );
        b2 = NS_chiedi_numero( NS_MINBASE, NS_MAXBASE, 10 );

        printf( "Immetti il numero da convertire: " );
        n = NS_chiedi_numero( NS_MINVAL, NS_MAXVAL, b1 );

        printf( "\n    base %2d: %s\n", b1, NS_ns(n,buff,b1) );
        printf( "    base %2d: %s\n\n", b2, NS_ns(n,buff,b2) );

        printf( "Vuoi effettuare un'altra conversione? "
                "(\"s\" per continuare) " );

        fgets( buff, NS_DIMBUFFNUM, stdin );
        ripeti = tolower(*buff) != 'n';

        /* se necessario, "svuota" stdin */
        while( buff[strlen(buff)-1] != '\n' )
            fgets( buff, NS_DIMBUFFNUM, stdin );

        printf( "\n\n" );
    } while( ripeti );

    return 0;
}
Ultima modifica effettuata da AldoBaldo 01/05/17 6:42
ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
01/05/17 9:32
E' ovviamente un "reinventare la ruota" dato che basterebbe scegliere una tra le tante funzioni già disponibili tra queste

strtod, _strtod_l, wcstod, _wcstod_l
strtol, wcstol, _strtol_l, _wcstol_l
strtoul, _strtoul_l, wcstoul, _wcstoul_l
_strtoi64, _wcstoi64, _strtoi64_l, _wcstoi64_l
_strtoui64, _wcstoui64, _strtoui64_l, _wcstoui64_l

e tra queste

sprintf, _sprintf_l, swprintf, _swprintf_l, __swprintf_l

(standard e non standard) che sono ampiamente documentate e (naturalmente) più testate.

Però il tuo lavoro merita apprezzamento e ti direi di migliorarlo aggiungendo, almeno, un paio di caratteristiche

1. gestione degli errori relativi al superamento dei limiti numerici

2. uso esclusivo di funzioni "sicure" per eliminare la possibilità di buffer overflow
01/05/17 10:37
AldoBaldo
Grazie, nessuno, mi hai indotto a fare qualche "ricerchina" alla quale non avrei pensato da solo (ad esempio su techonthenet.com/c_language/…), così che ho potuto scoprire che quel che sospettavo è vero: quel tipo di operazioni sono già svolte da funzioni consolidate e, meglio ancora, addirittura standard. Più che le funzioni che mi hai indicato, molte delle quali se non ho capito male sono tipiche dell'ambiente windows, mi intriga aver scoperto funzioni tipo strtoll() (che non conoscevo perché sul testo per il C che ho studiato io decenni fa non è citata, c'è solo strtol() e le sue compagne "unsigned" e "double" strtoul() e strtod() ). Altre funzioni sulla stessa linea che ho scoperto sono atoll(), strtold() e strtoull(). Ovviamente tutte quante includono i meccanismi per segnalare gli errori di "sforamento" che citi, documentati in dettaglio.

Se non ho capito male, si tratta di funzioni disponibili a partire dal C 90 (non è che io sia particolarmente pratico dell'evoluzione del C attraverso i secoli, però ho visto che in Code::Blocks c'è un'opzione per segnalare al compilatore la volontà di usare 'sto C 90).

Che ti devo dire, mi hai fatto scoprire cose utilissime che impiegherò senz'altro. Nello stesso tempo mi hai procurato una bella doccina di quelle gelate tirandomi coi piedi per terra :blush:. Ritengo di non aver comunque buttato via il mio tempo, se non altro baloccandomi ho fatto un po' d'esercizio e (importantissimo per me) MI SONO DIVERTITO. Sperimenterò.

Abbandono l'idea di inserire il codice tra i programmi di pierotofy.it, sarebbe una cosa vacua.
Ultima modifica effettuata da AldoBaldo 01/05/17 10:38
ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.