Почему не выдается предупреждение за неправильное использование __attribute __ ((pure)) в GCC? - PullRequest
3 голосов
/ 01 ноября 2019

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

#include <stdio.h>

static int a = 1;

static __attribute__((pure)) int pure_function(int x, int y)
{
        return x + y;
}

static __attribute__((pure)) int impure_function(int x, int y)
{
        a++;
        return x + y;
}

int main(void)
{
        printf("pure_function(0, 0) = %d\n", pure_function(0, 0));
        printf("impure_function(0, 0) = %d\n", impure_function(0, 0));

        return 0;
}

Я скомпилировал эту программу с gcc -O2 -Wall -Wextra, ожидая, что должна быть выдана ошибка или, по крайней мере, предупреждение для украшения impure_function() с __attribute__((pure)). Однако я не получил предупреждений или ошибок, и программа также запустилась без проблем.

Не помечены ли impure_function() с __attribute__((pure)) неправильными? Если да, то почему он компилируется без каких-либо ошибок или предупреждений, даже с флагами -Wextra и -Wall?

Заранее спасибо!

Ответы [ 2 ]

4 голосов
/ 01 ноября 2019

Это неправильно, и вы несете ответственность за правильное использование атрибута.

Посмотрите на этот пример:

static __attribute__((pure)) int impure_function(int x, int y)
{
        extern int a;
        a++;
        return x + y;
}

void caller()
{
    impure_function(1, 1);
}

Код, сгенерированный GCC (с -O1) для функцииcaller is:

caller():
        ret

Как видите, вызов impure_function был полностью удален, поскольку компилятор рассматривает его как «чистый».

GCC может пометить функцию как «чистую». "внутренне автоматически, если видит его определение:

static __attribute__((noinline)) int pure_function(int x, int y)
{
        return x + y;
}

void caller()
{
    pure_function(1, 1);
}

Сгенерированный код:

caller():
        ret

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

Я не думаю, что что-то мешает разработчикам GCC реализовать такое предупреждение, кроме времени, которое должно быть потрачено.

2 голосов
/ 01 ноября 2019

Чистая функция - это подсказка для оптимизирующего компилятора . Возможно, gcc не заботятся о чистых функциях, когда вы просто передаете ему -O0 (оптимизация по умолчанию). Поэтому, если f чисто (и определено вне вашей единицы перевода , например, в какой-то внешней библиотеке), компилятор GCC может оптимизировать y = f(x) + f(x); вчто-то вроде

{ 
  int tmp = f(x); /// tmp is a fresh variable, not appearing elsewhere
  y = tmp + tmp;
}

, но если f является не чистым (что является обычным случаем: представьте, что f вызывает printf или malloc), такая оптимизациязапрещено.

Стандартные математические функции, такие как sin или sqrt, являются чистыми (за исключением сумасшествия в режиме округления IEEE, см. http://floating -point-gui.de/ и Fluctuat для более подробной информации), и они достаточно сложны для вычисления, чтобы сделать такие оптимизации полезными.

Вы можете скомпилировать свой код с помощью gcc -O2 -Wall -fdump-tree-all дляугадайте, что происходит внутри компилятора. Вы можете добавить флаги -fverbose-asm -S, чтобы получить сгенерированный файл ассемблера *.s.

Вы также можете прочитать черновой отчет Bismon (особенно его раздел §1.4). Это может дать некоторые интуиции, связанные с вашим вопросом.

В вашем конкретном случае я предполагаю, что gcc означает вставку ваших звонков;и тогда чистота не имеет значения.

Если у вас есть время, вы можете написать собственный плагин GCC , чтобы сделать такое предупреждение. Вы потратите месяцы на написание этого! Эти старые слайды все еще могут быть вам полезны, даже если детали устарели.

На теоретическом уровне помните о теореме Райса . Следствием этого является то, что совершенная оптимизация чистых функций, вероятно, невозможна.

Имейте в виду ресурсный центр GCC , расположенный в Бомбее.

...