Ответ 1
В отношении чистого мы можем видеть из статьи Последствия чистых и постоянных функций, что чисто означает, что функция не имеет побочных эффектов и зависит только от параметров.
Итак, если компилятор может определить, что аргументы одинаковы, а память не изменилась между последующими вызовами, он может устранить последующие вызовы чистой функции, поскольку он знает, что чистая функция не имеет побочных эффектов.
Это означает, что компилятор должен выполнить анализ, чтобы определить, могли ли быть изменены аргументы чистой функции, прежде чем он сможет решить исключить последующие вызовы чистой функции для тех же аргументов.
Пример из статьи выглядит следующим образом:
int someimpurefunction(int a);
int somepurefunction(int a)
__attribute__((pure));
int testfunction(int a, int b, int c, int d) {
int res1 = someimpurefunction(a) ? someimpurefunction(a) : b;
int res2 = somepurefunction(a) ? somepurefunction(a) : c;
int res3 = a+b ? a+b : d;
return res1+res2+res3;
}
и показывает созданную оптимизированную сборку, которая показывает, что somepurefunction
вызывается только один раз, а затем говорит:
Как вы можете видеть, чистая функция вызывается только один раз, потому что две ссылки внутри тернарного оператора эквивалентны, а другая - дважды. Это связано с тем, что не было изменений в глобальной памяти, известных компилятору между двумя вызовами чистой функции (сама функция не могла ее изменить). Обратите внимание, что компилятор никогда не будет использовать многопоточность в учетной записи даже при запросе его явно через флаг -pthread), в то время как нечистой функции разрешено изменять глобальную память или использовать операции ввода-вывода.
Эта логика также применяется к указателю, поэтому, если компилятор может доказать, что память, указанная на указателе, не была изменена, то она может исключить вызов чистой функции, поэтому в вашем случае, когда компилятор видит:
x[1] = 'a';
он не может устранить второй вызов memcmp
, поскольку память, на которую указывает x
, изменилась.