Supponiamo di avere il seguente codice:Limitare l'accesso di campo tra due oggetti dello stesso tipo in gcc
typedef struct {
int f1;
int f2;
} t_str;
int f(t_str* p, t_str* q)
{
p[0].f1++;
q[0].f2++;
p[0].f1++;
q[0].f2++;
p[0].f1++;
q[0].f2++;
p[0].f1++;
q[0].f2++;
p[0].f1++;
q[0].f2++;
p[0].f1++;
q[0].f2++;
p[0].f1++;
q[0].f2++;
p[0].f1++;
q[0].f2++;
p[0].f1++;
q[0].f2++;
return 0;
}
Quando abbiamo compilarlo (io ho usato gcc-5.1.0) con -O3 opzione, il compilatore ottiene il seguente assembler:
f:
.LFB0:
.cfi_startproc
movl 8(%esp), %edx
movl 4(%esp), %ecx
movl 4(%edx), %eax
addl $9, (%ecx)
addl $9, %eax
movl %eax, 4(%edx)
xorl %eax, %eax
ret
.cfi_endproc
ciò significa che gcc ha deciso l'accesso al campo di f1 p e l'accesso al campo di f2 q Non alias. Immagino che ciò derivi dal presupposto che due oggetti dello stesso tipo non si sovrappongano mai o che siano uguali. Ma non ho trovato il problema in standard.
Quindi, per favore, qualcuno può trovare questo problema in standard, o un altro punto perché gcc ha limitato l'accesso al campo, o commenta cosa è successo?
UPD:
Beh, ho pensato a paragrafo 7 della sezione 6.5 troppo, ma sarebbe più comodo per me avere una cosa del genere in forma esplicita per tutti gli oggetti:
6,5. 16.1 semplice assegnazione
3 Se il valore essere memorizzato in un oggetto viene letto da un altro oggetto che si sovrappone in alcun modo la memorizzazione del primo oggetto, quindi la sovrapposizione è esatto ei due oggetti ha qualificato o versioni non qualificate di un tipo compatibile; in caso contrario, il comportamento è indefinito.
Purtroppo questa regola non può essere utilizzata qui.
ora guarda, se il codice sopra faccio la seguente funzione:
void main()
{
char * c = malloc(12);
memset(c, 0, 12);
f((t_str *)(c + 4), (t_str *)c);
printf("%d %d %d\n", ((t_str *)c)->f1, ((t_str *)c)->f2, ((t_str *)(c + 4))->f2);
}
Ora ho il seguente durante l'esecuzione:
$ gcc-5.1.0 test1.c -O3 && ./a.out
0 9 0
$ gcc-5.1.0 test1.c -O0 && ./a.out
0 18 0
Quindi, come pensi che sia questo codice è valido? Perché non sono sicuro se è conforme all'Articolo 7 della Sezione 6.5.
PS: cosa interessante:
$ gcc-5.1.0 test1.c -O3 -fwhole-program && ./a.out
0 10 0
$ gcc-5.1.0 test1.c -O3 -flto && ./a.out
0 10 0
Non sono sicuro di aver capito la tua domanda. Cosa intendi con "alias" e "sovrapposizione"? Che cosa sembra il compilatore sembra corretto, purché p e q non cambino tra gli accessi (ad esempio attraverso la gestione di un interrupt o giù di lì). Penso che potresti usare la parola chiave "volatile" per forzare il compilatore ad assumere che potrebbero essere cambiati. –
Per ulteriore divertimento, guarda cosa succede se dichiari 'int * pf1 = &p->f1; int * pf2 = &p->f2;' etc e ora sostituisci 'p-> f1 ++' con '(* pf1) ++'. –
alexanius si chiede se lo Standard escluda esplicitamente la possibilità per 'q' di puntare a' p-> f2'. Poiché la struttura 't_str' ha solo 2 membri' int', una matrice di 2 tali strutture potrebbe essere vista come contenente una terza di tali strutture all'indirizzo '& p-> f2'.Faccio finta che sia escluso, ma potrebbe essere più difficile creare un caso simile per 'typedef struct {int f [2]; } t_str; ' – chqrlie