Quindi, recentemente mi sono interessato a quanto bene il compilatore (gcc (GCC) 4.8.3
è quello in questione) sta ottimizzando i puntatori e i puntatori.Quando il compilatore dovrebbe essere prudente riguardo all'ottimizzazione della dereferenziazione del puntatore, se non del tutto?
Inizialmente ho creato un intero semplice e un puntatore intero e realizzato le operazioni su di esso in modo da poterlo stampare. Come previsto, tutte le operazioni che sono state codificate in modo rigido sono state ottimizzate, tramite il puntatore dereferenziato o meno.
call __main
leaq .LC0(%rip), %rcx
movl $1, %edx
call printf
E anche dopo la creazione di una funzione che prende in un puntatore a int, dereferenziazioni IT e cambia ancora era perfettamente optmized.
call __main
leaq .LC0(%rip), %rcx
movl $-1, %edx
call printf
Ora, quando ho trattato il mio puntatore come un vuoto e apportato delle modifiche gettandola a char e dereferenziazione, è in realtà ancora optmized perfettamente (una chiamata di 'extra' mov da quando ho inizialmente trattato come un 8 byte valore, e quindi come valore 1 byte per puntatore dereferenziazione)
call __main
movl $4, 44(%rsp)
movb $2, 44(%rsp)
leaq .LC0(%rip), %rcx
movl 44(%rsp), %eax
leal 1(%rax), %edx
call printf
quindi sulla mia domanda (s):
Quanto è coerente l'ottimizzazione del compilatore per quanto riguarda la dereferenziazione del puntatore? Quali sarebbero i casi in cui avrebbe scelto di essere conservatore?
Se tutti i miei indicatori in un progetto sono stati dichiarati con la parola chiave restrict, potrei fidarmi che sarebbe ottimizzato come se "nessun puntatore fosse utilizzato"?
(assumendo non ci sono volatile
casi)
Ps¹ .: Sono consapevole che il compilatore fa in genere un lavoro abbastanza buono, e che un programmatore preoccuparsi aiutare il compilatore in ottimizzazioni minori è, in generico, improduttivo (come molti indicano nello stackoverflow risponde alle domande relative all'ottimizzazione). Eppure ho ancora curiosità riguardo alla questione.
Ps² .: gcc -O3 -S -c main.c
è stato il comando utilizzato per generare il codice assembly
Codice C: (come richiesto)
1:
#include <stdio.h>
int main (void)
{
int a = 4;
int *ap = &a;
*ap = 0;
a += 1;
printf("%d\n", a);
return 0;
}
2:
#include <stdio.h>
void change(int *p) {
*p -= 2;
}
int main (void)
{
int a = 4;
int *ap = &a;
*ap = 0;
change(ap);
a += 1;
printf("%d\n", a);
return 0;
}
3:
#include <stdio.h>
void change(void *p) {
*((char*)p) += 2;
}
int main (void)
{
int a = 4;
void *ap = (void*) &a;
*((char*)(ap)) = 0;
change(ap);
a += 1;
printf("%d\n", a);
return 0;
}
'restrict' e' const' sono garanzie dal programmatore, non dal compilatore. Se interrompi il contratto, non sorprenderti a invocare UB – Olaf
Perché non includere anche il codice C che ti ha generato l'assembly che hai registrato? –
@JimBuck li ho aggiunti alla domanda. – SSWilks