Где это возможно, компилятор удалит эти накладные расходы за вас, сохраняя в регистре многократно используемые базовые расположения (например, p1->p2->p3
в вашем примере).
Однако иногда компилятор не может определить, какие указатели могут псевдоним другие указатели, используемые в вашей функции - это означает, что он должен возвращаться к очень консервативной позиции и часто перезагружать значения из указателей.
Здесь может помочь ключевое слово C99 restrict
. Он позволяет вам сообщать компилятору, когда некоторые указатели никогда не связываются с другими указателями в области действия функции, что может улучшить оптимизацию.
Например, возьмите эту функцию:
struct xyz {
int val1;
int val2;
int val3;
};
struct abc {
struct xyz *p2;
};
int foo(struct abc *p1)
{
int sum;
sum = p1->p2->val1 + p1->p2->val2 + p1->p2->val3;
return sum;
}
В gcc 4.3.2 с уровнем оптимизации -O1
он компилируется в код x86:
foo:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax
movl (%eax), %edx
movl 4(%edx), %eax
addl (%edx), %eax
addl 8(%edx), %eax
popl %ebp
ret
Как видите, он только один раз задерживает p1
- он сохраняет значение p1->p2
в регистре %edx
и использует его три раза для извлечения трех значений из этой структуры.