Будет ли GCC встроить функцию, которая принимает указатель? - PullRequest
14 голосов
/ 07 января 2010

У меня есть функция, которая работает с частью данных (скажем, int), и я хочу изменить ее на месте, передав ссылку на значение. Таким образом, у меня есть функция: void myFunction(int *thing) { ... }. Когда я использую это, я называю это так: myFunction(&anInt).

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

Сможет ли компилятор оптимизировать функцию, указав, что она будет работать непосредственно с моей переменной anInt?

Надеюсь, вы примете этот вопрос в том духе, в котором он задан (т.е. я не преждевременно беспокоюсь об оптимизации, мне любопытно получить ответ) Точно так же я не хочу превращать это в макрос.

Ответы [ 8 ]

18 голосов
/ 07 января 2010

Один из способов выяснить, является ли функция встроенной, - использовать параметр -Winline gcc:

-Winline
  Warn if a function can not be inlined and it was declared as inline.
  Even with this option, the compiler will not warn about failures to inline
  functions declared in system headers.

  The compiler uses a variety of heuristics to determine whether or not to
  inline a function. For example, the compiler takes into account the size
  of the function being inlined and the amount of inlining that has already
  been done in the current function.  Therefore, seemingly insignificant
  changes in the source program can cause the warnings produced by -Winline
  to appear or disappear.
9 голосов
/ 07 января 2010

GCC довольно умен. Рассмотрим этот фрагмент кода:

#include <stdio.h>

void __inline__ inc(int *val)
{
    ++ *val;
}

int main()
{
    int val;

    scanf("%d", &val);

    inc(&val);

    printf("%d\n", val);

    return 0;
}

После gcc -S -O3 test.c вы получите следующий соответствующий asm:

...
call    __isoc99_scanf
movl    12(%rsp), %esi
movl    $.LC1, %edi
xorl    %eax, %eax
addl    $1, %esi
movl    %esi, 12(%rsp)
call    printf
...

Как видите, не нужно быть экспертом asm, чтобы увидеть, что вызов inc () преобразован в инструкцию приращения.

7 голосов
/ 07 января 2010

Здесь есть две проблемы - можно ли оптимизировать код и будет ли он. Конечно, это может быть, но «воля» зависит от настроения оптимизатора. Если это действительно важно для вас, скомпилируйте код и посмотрите на вывод на языке ассемблера.

Кроме того, вы, кажется, смешиваете две проблемы. Встроенная функция эффективно вставляет свое тело на сайт вызова. Используете ли вы указатели или нет, ни здесь, ни там. Но вы, похоже, спрашиваете, может ли компилятор преобразовать:

int x = 42;
int * p = & x;
* p = * p + 1;

в

x = x + 1;

Это гораздо труднее увидеть оптимизатору.

2 голосов
/ 07 января 2010

Не имеет значения, является ли аргумент указателем или нет.

Но сначала, если компилятор должен автоматически встроить функцию, он должен быть статическим. И он должен содержаться в том же модуле компиляции. ПРИМЕЧАНИЕ: мы говорим о C, а не C ++. Встроенные правила C ++ отличаются.

Если невозможно использовать функцию в одном и том же модуле компиляции, попробуйте глобальную оптимизацию (подробности смотрите в документации вашего компилятора).

C99 дает вам ключевое слово "inline", как и в C ++. Что снимает ограничение на блок компиляции.

Вот некоторая дополнительная информация .

1 голос
/ 07 января 2010

Это будет (или, по крайней мере, может). Есть несколько причин, по которым функция не может быть встроена - например, когда вы пытаетесь получить доступ к указателю на функцию (вызывая функцию по ссылке - вы обращаетесь к параметрам по ссылке, что нормально). Может быть другая ситуация (статические переменные? Unsure)

Попробуйте объявить функцию с "extern inline" - это не даст компилятору выдавать автономное тело. Если он не может встроить функцию, он выдаст ошибку.

0 голосов
/ 07 января 2010

Если вы обеспокоены тем, что компилятор генерирует субоптимальный код, и хотите изменить простой тип значения, объявите вашу функцию как int myFunction(int) и верните новое значение.

0 голосов
/ 07 января 2010

Это выглядит как классический случай преждевременной оптимизации. Вы действительно знаете, что здесь есть проблема с производительностью? Стоит потратить свое драгоценное время на беспокойство. Я имею в виду, действительно знаю ? Мол, ты это измерил?

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

0 голосов
/ 07 января 2010

Какую версию компилятора вы используете? С какими вариантами? На какой платформе?

Все эти вопросы влияют на ответ. Вам действительно нужно скомпилировать код и посмотреть на сборку, чтобы быть уверенным.

...