Newsgroup: it.comp.lang.c
Titolo: array dentro strutture

Ciao a tutti,
mi rivolgo a voi in base ad un'interrogativo relativo all'utilizzo di
strutture contenenti array come valori di ritorno.
Ad esempio:
struct struttura
     {
      int a;
      int b;
      int vettore[10];
     } funzione(void);
Lo standard specifica che espressioni di questo tipo sono assolutamente
legali:
     f().a
     f().b
Semplicemente non sono degli L-value
Ma nel momento che scrivo:
    f().vettore[0]
capisco dal punto di vista logico cosa sto facendo, ma mi sembra di non
rispettare le regole di semantica del linguaggio. Mi spiego meglio, f
restituisce un valore struttura - che non è un L-value - e successivamente
seleziono il campo vettore. Dato che con l'operatore ., se il primo operando
non è un L-value, anche il campo selezionato non lo è.
Qui mi sorge la prima perplessità: se il nome di un vettore, che è un
L-value, decade ad un r-value di tipo puntatore al primo elemento - tranne
in quei famosi tre casi -, cosa capita nella suddetta espressione
f().vettore.
(Mi verrebbe da chiedere se esistono r-value di tipo array :-) ).
Riferendomi alla chiamata f().vettore[0]:
l'operatore e1[e2] è equivalente *(e1 + e2), eppure se sostituisco
nell'espressione *(f().vettore + 0) ottengo un errore in fase di
compilazione - gcc 2.95 con opzioni ansi -.
In secondo luogo, effettuare un'operazione di questo tipo non provoca un
comportamento non portabile?
Ovvero ragionando per assurdo, se la restituzione dei valori può avvenire
anche all'interno dei registri a seconda del tipo di compilatore utilizzato,
l'istruzione f().vettore[0] ,che utilizza l'aritmetica dei puntatori, come
può funzionare?
Grazie dell'attenzione.

Chiedo scusa, sicuri di non saper niente a proposito? Io sono nel dubbio piů
completo dato che su tre compilatori diversi ho ottenuto risultati diversi:
nel primo non si puň fare, nel secondo ottengo il caso appena presentato,
nel terzo tutto č permesso.
Grazie, ciao.

Scusate tanto, non è per far polemica, ma se la domanda è tanto cretina -
dato che nessuno mi ha risposto  - non me lo potevate dire subito. Inoltre,
leggendo i precedenti post di Andrea Griffini e Laforgia sulle strutture, mi
sembra assai impossibile che non sappiano trovare risposta sul quesito.
Quindi, dato che lo standard non è chiaro, nemmeno nell'ultimo draft quando
parla di valori struttura, rinnovo la domanda.
Ciao.

parla di valori struttura, rinnovo la domanda.
Boh... vediamo se qualcuno sa cosa rispondere...
Andrea

Una risposta che ho ricevuto sul quesito e' questa:
in C90 esistono i non-lvalue array e per questo
tipo di array non e' prevista la conversione dell'array
in puntatore al primo elemento. Quindi questo implica
che non risulta possibile accedere ad elementi di
questi array (e questo li rende di fatto inutilizzabili).
In C99 la conversione array->puntatore al primo elemento
e' invece prevista anche per i non-lvalue array e
l'indirizzo ottenuto e' utilizzabile solo sino al
successivo sequence point. In sostanza scrivere
   foo().v[2]
e' vietato in C90 ma permesso in C99 dove e' pero'
permesso anche scrivere *(foo().v+2).
Quindi gcc 2.95 sembra che permetta piu' di quanto
garantito dal C90 ma meno di quanto richiesto dal C99.
In pratica la scelta e' stata pur vietando la conversione
in indirizzo (come richiesto) di concedere come caso
particolare l'accesso ad un elemento per poterci fare
qualcosa comunque e questo significa che in quel
particolare frangente x[y] non e' quindi equivalente
a *(x+y) (uno strappo non standard alla regola).
HTH
Andrea

Grazie dell'interessamento Andrea,
quindi, il fatto che sia possibile la decandenza a puntatore al primo
elemento, indica che anche per l'array non-lvalue è allocata una memoria
temporanea  oppure è solamente una caratteristica di facciata utile solo al
compilatore?
Ciao.



Oltre una certa dimensione secondo me il ritorno per
struttura comporta (almeno su x86) che il chiamante
prepari lo spazio e che il chiamato ci scriva dentro.
Quindi in questo caso la memoria esiste eccome ma e'
memoria di stack del chiamante che viene potenzialmente
liberata non appena la chiamata termina. 
Il compilatore BCC55 mi sembra che usi sempre un'area di
memoria ma posticipa la distruzione di questa struttura
temporanea... ovvero con il codice:
   typedef struct S_ { int x,y; } S;
   S foo(int x,int y)
   {
     S s; s.x=x; s.y=y; return s;
   }
   int main()
   {
     S s = foo(10,20);
     printf("(%i,%i)\n",s.x,s.y);
     return 0;
   }
la funzione prima crea la struttura sullo stack e poi
nello statement di return la copia nella destinazione
puntata da eax (la zona di appoggio preparata dal chiamante
per poter ricevere la struttura). Il main poi prende i
dati da questa zona di appoggio e li copia in una
struttura locale (da cui poi vengono presi per la printf).
La cosa non ovvia (e su cui non si puo' secondo me fare
affidamento) e' che questa zona di appoggio in realta'
rimane allocata sino alla fine del main e non viene
invece liberata immediatamente.
gcc per una struttura contenente solo due interi
implementa il return usando una coppia di registri;
ma aumentando la dimensione della struttura lo spazio
per il valore di ritorno rimane allocato fra le variabili
locali della funzione come per BCC55 e non viene quindi
immediatamente recuperato.
Un altro compilatore pero' sarebbe autorizzato a
recuperare questo spazio immediatamente quindi con
il puntatore ad una struttura tornata per valore o
ad un suo campo non e' che ci possa fare molto (in
modo portabile).
Andrea

 ha scritto nel messaggio
news:3dc5a577...@news.tin.it...
