2015-07-09 5 views
14

Может ли кто-то прояснить, может ли функция (и почему) присваиваться функции pure или const, если у нее есть указательный параметр.Функции GCC pure/const, которые принимают аргумент указателя

Согласно GCC documentation:

Некоторые из распространенных примеров чистых функций StrLen или memcmp.

Весь смысл чистой функции является то, что он должен быть вызван только один раз для одних и тех же параметров, то есть результат может быть в кэше, если компилятор считает нужным сделать это, однако, как это работает для memcmp?

, например:

char *x = calloc(1, 8); 
char *y = calloc(1, 8); 

if (memcmp(x, y, 8) > 0) 
    printf("x > y\n"); 

x[1] = 'a'; 
if (memcmp(x, y, 8) > 0) 
    printf("x > y\n"); 

параметры для второго вызова memcmp идентичны первому (указатели указывают на тот же адрес), как компилятор знает, не использовать результат от первого позвонить, если memcmp является чистым?

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

ответ

3

Что касается чистого, то из статьи Implications of pure and constant functions видно, что чисто означает, что функция не имеет побочных эффектов и зависит только от параметров.

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

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

Пример из статьи выглядит следующим образом:

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 изменилось.

+1

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

+0

@ trideceth12 тот же анализ применяется и к указателям. –

+0

Итак, что произойдет, если 8 и 1 не известны во время компиляции? Например. они являются переменными? – Kata

3

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

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

С другой стороны, memcmp может не быть объявлен как const функции, поскольку она зависит от данных в памяти. Если это было const, компилятор мог применять более агрессивные оптимизации.

По этой причине было бы безопасно объявить функцию, которую вы хотите реализовать, как pure (но не const).

Смежные вопросы