вторник, 19 февраля 2008 г.

О практической пользе константных параметров...

Практики хорошего программирования рекоммендуют никогда не менять параметры функций в теле. Но чрезмерное применение const так загромождает прототип функции, не хочется, но альтернативы этому нету. const'ом метод не испортишь :) и параметр, как показывает практика - тоже.

Не далее как вчера описывал точки входов системных вызовов в ядро. Логика ассемблерной прослойки проста - сохранить все кроме eax, вызвать высокоуровневый метод-обработчик и корректно же выйти. Но это выливается примерно в такой код:

KernelWait:
pushfl
pushl %ebx
pushl %ecx
pushl %edx
pushl %esi
pushl %edi
pushl %ebp

pushl %ds
pushl %es
movl $KERNEL_DATA_SELECTOR, %ebx
movw %bx, %ds
movw %bx, %es

pushl %edx
pushl %ecx
pushl %ebx
pushl %eax
call StubWait
add $16, %esp

popl %ds
popl %es

popl %ebp
popl %edi
popl %esi
popl %edx
popl %ecx
popl %ebx
popfl

iret

Глядя на эту функцию часть кода может показаться лишней. Вполне логично было бы написать так:

KernelWait:
...
pushl %edx
pushl %ecx
pushl %ebx
pushl %eax
call StubWait
add $4, %esp
popl %edx
popl %ecx
popl %ebx
...
iret

Но если сделать так, то любое изменение параметра функции в ее теле повлечет за собой изменение регистра приложения, который мы не должны менять.

int StubWait (int a, int b, int c, int d)
{
d += 10;

Очень плохо! Разумным способом предотвращения данной ситуации является описание всех параметров константными.

int StubWait (const int a, const int b, const int c, const int d)
{
int dnew = d + 10;

Так значительно лучше и не грозит проблемами. Кроме того думаю, что привычка объявлять все методы функций константными даст компилятору больший простор для оптимизации. Это предположение, но компиляторы сейчас умные, обявление константости в следующем случае:

static const
struct console StubXGAConsole = {
.putc = StubXGAPutC,
.getc = StubXGAGetC,
};

static const
struct console *sConsole = &StubXGAConsole;

позволило компилятору, при отсутствии явной модификации sConsole, вообще атрофировать эту переменную, не смотря на то, что сам по себе sConsole модифицируемый.

PS: А экономия на push/pop очень напоминает преждевременную оптимизацию, к тому же нелогично после вызова функции пупать параметры обратно, поэтому лучше я воздержусь от такого вида оптимизации. Тем более что я использую единственный макрос для всех 8 системных вызовов.