KR Puntatore a struttura anonima

di il
23 risposte

KR Puntatore a struttura anonima

Ciao a tutti,
volevo porvi una questione relativa a quanto scritto sul K&R al capitolo 6.2.
Dopo un'introduzione chiara sulle strutture dati, la presentazione dei puntatori e la doppia notazione per accedere ai membri delle medesime, operatori (.) e (->), soffermandosi anche sulla precedenza degli operatori a tal proposito a un certo punto viene dichiarata la seguente struttura anonima:

struct {
	int len;
	char *str;
} *p;
Dichiarando contestualmente un suo puntatore (*p).

Immediatamente dopo per far osservare che l'opearotore "->" ha precedenza sull'operarore "prefisso" ++ scrive:

++p->len;
Ma senza troppo dubitare questo frammento di codice va in segmentation fault. Evidentemente perché il puntatore p non punta ancora a nessuna zona di memoria valida. E' un errore espositivo o il K&R dà per scontato, secondo voi, che il puntatore sia successivamente inizializzato? Ma data per buona questa ipotesi come posso assegnare un indirizzo partendo da una struttura anonima? In generale a cosa serve una struttura anonima? Inoltre, perché non posso assegnare un valore di inizializzazione durante la dichiarazione della struttura? Infatti il seguente frammento mi dà errore:

struct {
	int len = 10;
	char *str;
} *p;
In conclusione per far "funzionare" il frammento
++p->len;
ho dovuto rendere la struttura non anonima dichiarare "un'istanza" e assegnarne l'indirizzo al puntatore, nel seguente modo:

struct oggetto {
          int len;
          char *str;
      } *p;
      
      
      struct oggetto o;
      o.len = 10;
      o.str = "Sono un array di caratteri di soprannome stringa.";
      p = &o;
      p->len = 5;
      
      printf("++p->len %d\n",++p->len);

Chiedo anticipatamente scusa se non ho compreso appieno il senso del testo e vi ringrazio per i chiarimenti che vorrete fornirmi.

Un saluto e buona giornata.

23 Risposte

  • Re: KR Puntatore a struttura anonima

    Regola di buona programmazione: anche se si puo' fare, meglio non farlo.

    della serie: farsi i selfie sul ciglio di un burrone/balcone/... facendo un passo all'indietro, si puo' fare, ma non e' una grande idea (e su youtube se ne trovano diversi questi astutoni)

    1) MAI usare strutture anonime
    2) MAI modificare il valore dei puntatori (pena lo strappi delle unghie)
    3) se il puntatore punta ad un array, usare SEMPRE gli indici
    4) MAI avere a che fare con l'aritmetica dei puntatori (pena lo strappo di due palline )
    5) inizializzare SEMPRE I puntatori, ed in generale QUALUNQUE variabile, ANCHE se non servirebbe.

    E' OVVIO che un puntatore dovrebbe puntare a qualcosa se lo si vuole usare!
  • Re: KR Puntatore a struttura anonima

    Migliorabile, i tuoi consigli li intendi come consigli da "ambito didattico" o attribuisci loro valore assoluto?

    Chiedo perché alcune delle pratiche che hai elencato le uso abitualmente senza incorrere in alcun problema.

    1) delle strutture anonime, in effetti, non saprei che farmene, per cui non le ho mai usate -- a cosa servono?
    2) se intendi che non bisogna mai perdere l'indirizzo di un frammento di memoria allocata dinamicamente sono d'accordo, ma... mi capita spesso di copiare quell'indirizzo in un puntatore ausiliario (alias?) per poi modificare quello secondo necessità
    3) proprio usando un alias ausiliario non ho mai avuto problemi a "scorrere" un array tramite puntatori
    4) sono incorso in situazioni nelle quali ho trovato molto pratica l'aritmetica dei puntatori; ammetto che esagerando si rischia d' infilarsi in situazioni non immediatamente chiare che, in effetti, evito come la peste (anche perché per scoprire gli eventuali errori in fase di debug mi parte il cervello)
    5) Oh, yes! Un puntatore che punta "chissà dove" è un pessimo compagno di viaggio; mi viene un paragone: è come tenere in mano una pistola carica e scherzare col grilletto senza neppure guardare dove la si sta puntando...
  • Re: KR Puntatore a struttura anonima

    VALORE ASSOLUTO e scolpito nella pietra, ovviamente
    E il tuo punto 4) SECONDA PARTE, e' la conferma
    L'aritmetica dei puntatori non serve a niente!
    Trova un esempio in cui non puoi fare la stessa cosa con gli indici e il sizeof
  • Re: KR Puntatore a struttura anonima

    Ho letto con attenzione tutti i vostri interventi, preziosi e vi ringrazio.
    Alla fine non ho capito se hanno un senso le strutture anonime (mi ricordano le classi anonime in altri linguaggi - ma in questo caso mi è ben chiaro il loro utilizzo) ma non credo sia calzante con un struttura anonima in C.

    Per quanto riguarda l'aritmetica dei puntatori posso trovare, esprimendo la mia opinione con molta umiltà, consapevole della mia bassa esperienza in C, vere le posizioni sia di chi dice di evitarle come la peste e chi ha una posizione di mezzo.

    Pur tuttavia, qualche giorno fa avevo aperto un thread, sugli array multi-dimensionali e di come in fondo ogni array multi-dimensione in realtà in memoria per la natura fisica della stessa in fondo sia una struttura sostanzialmente monodimensionale e chiedevo, considerando la necessità di gestire grandi moli di dati se l'aritmetica di puntatori non siano più performani rispetto ad una accesso con indice. In fondo accedendo con gli indici occorre tradurre a più basso livello a un accesso mono-dimensionale. Mi chiedevo anche se questo lavoro lo faccia il compilatore per noi.
    Ma infine, viene spontanea perché a distanza di anni e di revisione dell'ANSI C l'aritmetica dei puntatori continuino ad esistere.

    Grazie ancora per tutto quanto avete scritto e per quanto vorrete ancora ulteriormente integrare rispetto a queste considerazioni.

    Ma alla fine il K&R ha scritto un esempio sbagliato o dava per scontato che il lettore desse per scontato che quel puntatore prima dovesse essere inizializzato, benché nel testo sia usato senza farlo....

    Insomma, una struct anonima a che serve?
    Un saluto a tutti
  • Re: KR Puntatore a struttura anonima

    Migliorabile: "Trova un esempio in cui non puoi fare la stessa cosa con gli indici e il sizeof"

    Perché il sizeof? Non capisco a cosa ti riferisci. Per esempio, se ho un puntatore p a un array di int (diciamo int a 32 bit, quattro byte) e faccio *(p+7) accedo al settimo elemento dell'array, "spostandomi" in avanti di 28 byte senza dover specificare le dimensioni dell'int, o no? Che c'entra il sizeof? Mi spieghi cosa volevi dire?
  • Re: KR Puntatore a struttura anonima

    AldoBaldo ha scritto:


    accedo al settimo elemento
    Ottavo...
  • Re: KR Puntatore a struttura anonima

    E' vero:
    p+0, p+1, p+2, p+3, p+4, p+5, p+6, p+7... zero based.
    Lo so bene, ovviamente, però per qualche ragione "neuronale" ho scritto altrimenti. Hai fatto benissimo a puntualizzare.
  • Re: KR Puntatore a struttura anonima

    Insomma ragazzi
    proprio non mi volete dire come la pensate al riguardo delle questioni che ponevo da principiante
    Comunque, consapevole delle insidie, credo che l'aritmetica dei puntatori sia una gran cosa. Quello che vorrei sapere se vi sono motivi, nei casi di grandi moli di dati, usare l'aritmetica dei puntatori o meno. O il compilatore risolve la questione prima di tradurre tutto in codice macchina?

    Un saluto a tutti.
  • Re: KR Puntatore a struttura anonima

    In realtà il quesito non è chiaro.

    Che vuoi sapere esattamente?

    Se quella linea del testo era sbagliata? No è evidente che sta facendo un discorso sulle precedenze; è scontato che i puntatori devono essere validi.

    Vuoi sapere se l'aritmetica dei puntatori può essere usata? Qualcosa sulle strutture anonime? Su cosa fa il compilatore?

    Insomma c'è un po' di confusione...
  • Re: KR Puntatore a struttura anonima

    oregon ha scritto:


    In realtà il quesito non è chiaro.

    Che vuoi sapere esattamente?

    Se quella linea del testo era sbagliata? No è evidente che sta facendo un discorso sulle precedenze; è scontato che i puntatori devono essere validi.

    Vuoi sapere se l'aritmetica dei puntatori può essere usata? Qualcosa sulle strutture anonime? Su cosa fa il compilatore?

    Insomma c'è un po' di confusione...
    Oregon,
    un illustre pensatore diceva: "Non esiste un obbligo a capire, esiste un obbligo a farsi capire". Dunque chiedo scusa, in effetti la mia esposizione è stata ondivaga e non a focalizzato una questione in particolare.
    Per quanto riguarda il K&R,l'esempio che leggevo stamattina all'alba, col passare delle ore mi è parso chiaro che stesse concentrandosi sulla priorità degli operatori e che quindi desse per scontato che poi il puntatore dovesse essere inizializzato.

    Quello che cercavo di comprendere, date le risposte e gli altri interventi e anche alcuni miei thread fa, è se esiste un differenza di performance nell'utilizzo dell'aritmetica dei puntatori, rispetto all'utilizzo dei più "usuali" indici. Sto riflettendo, a strutture dati ampie, ovviamente. Dove la mole dei dati potrebbe significativa. Allo stesso tempo mi domando se in realtà il compilatore da un codice scritto con gli indici non risolva lui la questione.
    La mia ipotesi di una maggiore performance dell'aritmetica dei puntatori sugli indici è che comunque la memoria, seppur non utilizzata in modo totalmente contigua, è uno spazio monodimensionale.

    Spero di essere stato un po' più chiaro, mi scuso ancora per la poca chiarezza.

    Grazie ancora.
  • Re: KR Puntatore a struttura anonima

    se esiste un differenza di performance nell'utilizzo dell'aritmetica dei puntatori, rispetto all'utilizzo dei più "usuali" indici.
    No
    se in realtà il compilatore da un codice scritto con gli indici non risolva lui la questione.

    un illustre pensatore
    Scusa tu se vado al concreto e non mi occupo di grandi pensatori ...
  • Re: KR Puntatore a struttura anonima

    oregon ha scritto:


    se esiste un differenza di performance nell'utilizzo dell'aritmetica dei puntatori, rispetto all'utilizzo dei più "usuali" indici.
    No
    se in realtà il compilatore da un codice scritto con gli indici non risolva lui la questione.

    un illustre pensatore
    Scusa tu se vado al concreto e non mi occupo di grandi pensatori ...
    Grazie Oregon,
    ovviamente l'allusione al grande pensatore nostro connazionale era una critica rivolta a me stesso ovviamente. Allora, perdonerai la domanda, poi prometto di chiudere il thread. Qual è il vero apporto di vantaggio di usare l'aritmetica dei puntatori? Perché permane lungo la sua evoluzione dello standard ANSI del C?

    Grazie per questo e tutti i tuoi altri interventi.
    Un saluto.
  • Re: KR Puntatore a struttura anonima

    Guarda ... tutti i compilatori moderni riescono a gestire puntatori ed indici in maniera adeguata. Ad esempio, Visual C++, quando compila due linee di questo tipo

    *(p + ix) = 16;
    p[ix] = 16;

    (premesso che p è un puntatore ad int valido e che ix è un int che vale 5), genera queste linee assembly per la CPU (anche se non lo conosci, sono semplici) ... Ti accorgerai che la compilazione delle due linee è la medesima, a parte l'uso di registri simili

    12: *(p + ix) = 16;
    00AF1014 8B 45 FC mov eax,dword ptr [ix]
    00AF1017 8B 4D F8 mov ecx,dword ptr [p]
    00AF101A C7 04 81 10 00 00 00 mov dword ptr [ecx+eax*4],10h
    13:
    14: p[ix] = 16;
    00AF1021 8B 55 FC mov edx,dword ptr [ix]
    00AF1024 8B 45 F8 mov eax,dword ptr [p]
    00AF1027 C7 04 90 10 00 00 00 mov dword ptr [eax+edx*4],10h

    Solo in certi casi (ad esempio con la presenza di costanti) si può notare qualche differenza di compilazione, che rende il puntatore un po' più veloce (per la presenza di 1 o 2 istruzioni in meno) ma dipende molto dal compilatore e dal grado di ottimizzazioni.

    In generale si può tranquillamente dire che le notazioni sono equivalenti e che l'uso dei puntatori giustifica (alla nascita del C) l'aritmetica dei puntatori. Niente di più.

    Ma in determinate situazioni, l'uso dell'aritmetica dei puntatori rende il codice più compatto (e quindi veloce) rispetto a come dovresti scriverlo per fare la stessa cosa con gli indici.
  • Re: KR Puntatore a struttura anonima

    oregon ha scritto:


    Guarda ... tutti i compilatori moderni riescono a gestire puntatori ed indici in maniera adeguata. Ad esempio, Visual C++, quando compila due linee di questo tipo

    *(p + ix) = 16;
    p[ix] = 16;

    (premesso che p è un puntatore ad int valido e che ix è un int che vale 5), genera queste linee assembly per la CPU (anche se non lo conosci, sono semplici) ... Ti accorgerai che la compilazione delle due linee è la medesima, a parte l'uso di registri simili

    12: *(p + ix) = 16;
    00AF1014 8B 45 FC mov eax,dword ptr [ix]
    00AF1017 8B 4D F8 mov ecx,dword ptr [p]
    00AF101A C7 04 81 10 00 00 00 mov dword ptr [ecx+eax*4],10h
    13:
    14: p[ix] = 16;
    00AF1021 8B 55 FC mov edx,dword ptr [ix]
    00AF1024 8B 45 F8 mov eax,dword ptr [p]
    00AF1027 C7 04 90 10 00 00 00 mov dword ptr [eax+edx*4],10h

    Solo in certi casi (ad esempio con la presenza di costanti) si può notare qualche differenza di compilazione, che rende il puntatore un po' più veloce (per la presenza di 1 o 2 istruzioni in meno) ma dipende molto dal compilatore e dal grado di ottimizzazioni.

    In generale si può tranquillamente dire che le notazioni sono equivalenti e che l'uso dei puntatori giustifica (alla nascita del C) l'aritmetica dei puntatori. Niente di più.

    Ma in determinate situazioni, l'uso dell'aritmetica dei puntatori rende il codice più compatto (e quindi veloce) rispetto a come dovresti scriverlo per fare la stessa cosa con gli indici.
    Oregon che dire... grazie per la tua magnifica esposizione e spiegazione. Di Assembly o delle vaghe riminiscenze, per le cose che vorrei andare a trattare, una rinfrescatina non guasterebbe.
    In effetti mi davo come spiegazione la compattezza, alcune espressioni scritte con i puntatori ed aritmetica sono talmente compatte da essere disarmanti e questo può comportare un incremento di performance, ma pensavo che fosse un modo di scrivere il codice più vicino a come è l'hardware, ma avevo il dubbio che poi dietro le quinte agisse il compilatore…
    Solo in certi casi (ad esempio con la presenza di costanti) si può notare qualche differenza di compilazione
    Rifletterò e indagherò su quanto hai scritto sopra. Grazie, per questa ulteriore riflessione.

    Io uso GCC (in ambiente linux) e sempre GCC nella forma di cygwin sotto windows. Scusa l'ignoranza, in queste date condizioni cosa posso usare per leggere l'assembly dal compilato?


    Grazie davvero di cuore per la tua bellissima illustrazione, che mi stimola anche a riprendere in mano vecchi riminiscenze. Grazie ancora!
Devi accedere o registrarti per scrivere nel forum
23 risposte