Un consiglio su dubbi di "stile" in 'C'

di il
25 risposte

Un consiglio su dubbi di "stile" in 'C'

Salve

voi lo sapete che mi considero un programmatore giocattolo, ma mi ci impegno a migliorare

stanotte l'insonnia mi ha fatto pensare
e pensare mi ha portato a farmi alcune domande

il tutto ha portato a un programmino di esempio che compila completamente e senza warning
ma non mi convince del tutto

si tratta di una "maniera" per truccare su puntatori a costante
sì, lo so che non si fa, ma la domanda che mi pongo è:
perché non ho warning
cominciamo coi dettagli importanti:
sistema operativo: Linux Ubuntu 18.04 x64 LTS Mate
ambiente: Geany 1.32
gcc: versione 7.5
insomma la versione "di serie" col mio SO
stringa di compilazione:
gcc -Wpedantic -c "%f"
ma anche
gcc -Wall -c "%f"

che dovrebbero essere i più alti livelli di warning, se ho capito bene

e quindi la mia domanda è:
perchè il programma compila senza warning, con tutte le "cattiverie" che ho fatto alla povera costante?
ho lasciato dentro i miei dubbiocommenti...


ecco il programma:

/*
 * punta.c
 *
 * 15-12-2020 Nelson "Standardoil"
 * Sentitevi liberi di trarre ispirazione
 * L'ammiraglio non si offende
 *
 *
 */


#include <stdio.h>

int main(int argc, char **argv)
{
   const int a = 0;
   int * pp = 0;
   pp = (void *) &a;
   // letto a rovescio: indirizzo di costante, castato esplicitamente a puntatore void, castato automaticamente a puntatore a intero
   // non da warning, sarà normale?
   printf("A vale: %d\n", a);
   // e qui stampa la variabile, non mi lamento
   char prova[] = "A Vale: %d\n";
   *pp = 1;
   // qui altero una costante attraverso un puntatore che formalmente NON è puntatore a costante
   // sarà normale?
   printf(prova, a);
   // e qui lo stampa, usando come stringa di formato un array di char
   // ero convinto fosse vietato, forse avevo capito male
   // credevo che la stringa di formato dovesse essere una costante letterale, come nella prima stampa
   * (int *)(void *) &a = 2;
   // qui poi altero la costante senza nemmeno passare per una variabile puntatore esplicita
   // ma castando due volte l'indirizzo della costante
   // questo mi sembra ancora meno normale
   char * prova2 = "A VALE: %d\n";
   printf(prova2, a, a);
   // e lo stampo usando un puntatore a carattere come stringa di formato
   // oltretutto passando un parametro in più
   // qui è giusto che non ci siano warning, dato che la funzione fprintf è variadica
   // ma la domanda è:
   // si tratta di buona programmazione?
   return 0;
}


Edit, perché non era chiaro, mi scuso per non averlo specificato

Naturalmente stampa prima 0, poi 1 e poi 2
Altrimenti non avrebbe avuto senso, questo mio post

25 Risposte

  • Re: Un consiglio su dubbi di "stile" in 'C'

    Il valore di a non cambia, il compilatore considera che il valore di a sia sempre 0 anche se lo modifichi.
  • Re: Un consiglio su dubbi di "stile" in 'C'

    Win7 32bit, CODE::BLOCKS, MinGW, warning tutti attivi.
    Il tuo codice non segnala nessun warning, restituisce sempre il valore di a, anche se gli assegno un valore diverso da zero, sia positivo che negativo.
    Alle domande che hai posto non so rispondere... sarei felice se qualcuno rispondesse.

    EDIT:
    Non ho segnalato i due warning per le variabli: argc e argv, dichiarate e mai utilizzate, perché ininfluenti.
  • Re: Un consiglio su dubbi di "stile" in 'C'

    Per Oregon:

    No

    Stampa 0, poi 1 poi 2

    Altrimenti non mi ponevo alcuna domanda, scusa...


    E aggiungo:
    La mia domanda non è relativa al fatto che il valore cambia
    Che cambi è ovvio, dato che ho accesso all'area di memoria che lo contiene e la modifico, sarebbe comportamento sbagliato se NON cambiasse

    La mia domanda riguarda il perché non ho 'almeno' un warning dal compilatore, che mi lascia fare quello che voglio ad una costante
  • Re: Un consiglio su dubbi di "stile" in 'C'

    Per Rubik
    Nemmeno io ho considerato quei due parametri
    L'argomento infatti è un altro
  • Re: Un consiglio su dubbi di "stile" in 'C'

    Il tuo codice mi stampa 0, 0, 0
    se metto a=5 all'inizio, mi stampa: 5, 5, 5
  • Re: Un consiglio su dubbi di "stile" in 'C'

    A me no

    Adesso non riaccendo il PC, c'è Pieraccioni

    Ma il funzionamento sbagliato è quello che riscontri tu, visto che se alteri l'area di memoria la variabile deve cambiare

    Prova a mettere 'volatile' la variabile
  • Re: Un consiglio su dubbi di "stile" in 'C'

    No. È corretto 0 0 0 come anche vc++ fa.
  • Re: Un consiglio su dubbi di "stile" in 'C'

    Ne parliamo domani

    Ma io non parlo a vuoto

    Prova semmai a mettere volatile la variabile

    Oppure a stamparla tramite puntatore (a costante)

    Scommettiamo che la trovi cambiata?

    Come ho detto il mio problema è sull'assenza di warning, non sul fatto che la variabile cambia
  • Re: Un consiglio su dubbi di "stile" in 'C'

    Warning non ce ne sono neanche con vc++ perché la 'variabile' non varia dato che è una costante!

    Ovviamente questo finché nel tuo codice usi proprio a e non il suo valore con il puntatore.

    Ovvero

    printf di a -> 0

    cambi a con il puntatore e fai
    printf del contenuto puntato dal puntatore -> 1

    subito dopo fai
    printf di a -> ancora 0!
  • Re: Un consiglio su dubbi di "stile" in 'C'

    Non è una costante, avendo un indirizzo di memoria non lo è
    
    max@LastMax:~/C$ ./punta
    A vale: 0
    A Vale: 1
    A VALE: 2
    max@LastMax:~/C$ 
    
    come vedi stampa 0 poi 1 poi 2

    probabilmente hai qualche ottimizzazione che non ti riaggiorna il valore di a tra una stampata e l'altra, prova a metterla volatile,

    adesso faccio due prove di esempio per indicare bene il mio dubbio
  • Re: Un consiglio su dubbi di "stile" in 'C'

    Grazie per i tuoi consigli ma non ci sono problemi con il compilatore che uso. Il risultato corretto è 0 0 0 e l'indirizzo di memoria non importa, è il compilatore a gestire la costante.

    Hai usato per compilare lo switch

    -pedantic-errors

    ?
  • Re: Un consiglio su dubbi di "stile" in 'C'

    Se scrivessi
    
    #include <stdio.h>
    
    int main()
    {
       const int a = 0;
       a=2:
       return 0;
    }
    
    avrei un errore di compilazione:
    
    gcc -Wpedantic -c "punta1.c" (nella cartella: /home/max/C)
    punta1.c: In function ‘main’:
    punta1.c:6:5: error: assignment of read-only variable ‘a’
        a=2;
         ^
    Compilazione fallita.
    
    che non è nemmeno un warning, ho proprio compilazione fallita, impossibile modificare il valore


    se invece scrivessi:
    
    #include <stdio.h>
    
    int main()
    {
       const int a = 0;
       int * b=&a;
       *b=1;
       return 0;
    }
    
    ho una cosa così:
    
    gcc -Wall -o "punta1" "punta1.c" (nella cartella: /home/max/C)
    punta1.c: In function ‘main’:
    punta1.c:6:12: warning: initialization discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
        int * b=&a;
                ^
    Compilazione terminata correttamente.
    
    che è solo un warning, infatti compila ma mi segnala che sto assegnando ad un puntatore un indirizzo di variabile const
    notare che non ho errore quando poi scrivo nell'area di memoria, è nell'inizializzazione del puntatore il warning, non nella scrittura in memoria

    e stampa
    
    #include <stdio.h>
    
    int main()
    {
       const int a = 0;
       printf("la variabile vale: %d\n",a);
       int * b=&a;
       *b=1;
       printf("la variabile vale: %d\n",a);
       return 0;
    }
    
    compila
    
    gcc -Wpedantic -c "punta1.c" (nella cartella: /home/max/C)
    punta1.c: In function ‘main’:
    punta1.c:7:12: warning: initialization discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
        int * b=&a;
                ^
    Compilazione terminata correttamente.
    
    e stampa
    
    max@LastMax:~/C$ ./punta1
    la variabile vale: 0
    la variabile vale: 1
    max@LastMax:~/C$ 
    

    e quindi la questione che la variabile non si può modificare è chiusa, grazie

    torniamo all'esempio del mio primo programma
    
    #include <stdio.h>
    
    int main()
    {
       const int a = 0;
       printf("la variabile vale: %d\n",a);
       * (int *) &a = 1;
       printf("la variabile Vale: %d\n",a);
       return 0;
    }
    
    
    dove casto a puntatore a intero l'indirizzo della costante e lo uso per alterare la costante

    compila, senza warning (è questa la domanda)
    
    gcc -Wall -o "punta1" "punta1.c" (nella cartella: /home/max/C)
    Compilazione terminata correttamente.
    
    
    ed esegue
    
    max@LastMax:~/C$ ./punta1
    la variabile vale: 0
    la variabile Vale: 1
    max@LastMax:~/C$ 
    
    come si vede ho cambiato una maiuscola, per dimostrare che il programma è l'ultimo compilato
  • Re: Un consiglio su dubbi di "stile" in 'C'

    -pedantic-errors
  • Re: Un consiglio su dubbi di "stile" in 'C'

    oregon ha scritto:


    Grazie per i tuoi consigli ma non ci sono problemi con il compilatore che uso. Il risultato corretto è 0 0 0 e l'indirizzo di memoria non importa, è il compilatore a gestire la costante.
    torno a dire, onn è possibile quello che dici

    prova a fare questo
    
    #include <stdio.h>
    
    int main()
    {
       const int a = 0;
       printf("la variabile vale: %d\n",a);
       int * p = (int *) &a;
       *p=1;
       printf("la variabile Vale: %d\n",* p);
       printf("i due puntatori sono uguali: %p, %p\n",(void *) &a, (void *) p);
       return 0;
    }
    
    
    
    vedrai che i due puntatori sono uguali, quindi le due aree di memria sono uguali, quindi se ne modifichi una modifichi anche l'altra

    oppure prova a usare la variabile in qualche calcolo, oppure dichiarala volatile, perché il suo valore è cambiato, la mia è una affermazione
Devi accedere o registrarti per scrivere nel forum
25 risposte