Расширения GCC: Как использовать встраиваемые функции в качестве макросов




Сайт создан в системе uCoz
Вернуться к Оглавлению

 

Автор: Andrey Rjavskov(Rzhavskov) as rjaan <rjaan@yandex.ru>


1.Введение

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

Влияние встраиваемых функций на размер кода является непредсказуемым и все зависит от соответствующего случая, когда код объекта может быть больше или меньше. Так же можно заставить GCC попытаться интегрировать все «достаточно простые» функции во внутрь вызывающей их функций с использованием опции -finline-functions.

GCC выполняет три различных семантик декларации inline-функции:

  1. первый доступен с -std=gnu89 или -fgnu89-inline или когда атрибут gnu_inline представлен во всех inline-декларациях;
  2. другой, с -std=c99, -std=c11, -std=gnu99 или -std=gnu11 (без -fgnu89-inline)
  3. последний используется при компиляции C++.

2.Использование

Для декларации inline-функции следует использовать ключевое слово inline, наподобие этого:

static inline int

inc (int *a)

{

return (*a)++;

}

Если вы пишете заголовочный файл в соответствии с стандартом ISO C90, взамен inline используйте __inline__ (См. Альтернативные ключевые слова).

Три типа встраивания, перечисленных ранее во ведении, ведут себя одинаково в двух случаях, когда ключевое слово используется в статической, как в выше показанном примере, и когда функция в первые декларируется без использования ключевого слова inline, а затем определяется с ним, наподобие этого:

extern int inc (int *a);

inline int

inc (int *a)

{

return (*a)++;

}

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

В случае, когда функция является встраиваемой и статической, если все вызовы этой функции интегрированы в внутри вызывающей функции, а её адрес никогда не будет использован, соответственно ассемблерный код такой функции никогда не будет использован. В этом случае, GCC на самом деле не создаст ассемблерный код этой функции, кроме тех случаев, когда использована опция -fkeep-inline-functions. Некоторые вызовы не могут быть интегрированы из-за различных причин(на практике, вызовы, которым предшествует определение функции не могут быть интегрированы, в прочем как не один из рекурсиных вызовов внутри данного определения). Если существуют не интегрированные вызовы, тогда функция будет коипилироваться в ассемблерный код как обычно. Функция так же будет компилироваться как обычно, если программа ссылается на её адрес, потому что тот не может быть использован.

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

Как требует ISO C++, GCC считает членами функций, определенных в теле класса, которые будут маркироваться встраиваемыми даже, если они не имеют в своей декларации ключевое слово inline. Вы можете отменить это опцией -fno-default-inline, см Опции управления диалектом С++.

GCC не встроит ни какие фукции, когда не используется оптимизация, http://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Optimize-Options.html, кроме случая, когда в прототипе этой функции указан атрибут `always_inline', наподобие этого:

/* Прототип */

inline void foo (const char) __attribute__((always_inline));

3. Особенности использования с стандартом GNU C90

При встраивании встраиванию в соответствии с стандартом GNU C90 имеется воя специфика использования inline-функций

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

Если Вы одновременно указали в определении функции inline и extern, тогда определение будет использавано только для механизма встраивания. В этом случае сама функция не будет компилироваться, даже если вы укажете явно её адрес. Такой адрес становится внешней ссылкой, как если бы вы только объявили функцию, и не определили ее.

Комбинация ключевых слов inline и extern почти всегда приводит к эффекту макроподстановки. Такой способ использования этих ключевых слов позволяет положить определение функции в заголовочный файл, а другую копию этого определения (с отсутствующими inline и extern) в библиотечный файл. Такой способ определения в заголовочном файле при вызовах данной функции будет приводить к встраиванию функции. Если вызовы к функции все ещё остаются, тогда они будут отправлены к единственной копии в библиотеке.

6.БИБЛИОГРАФИЯ

  1. Extensions to the C Language Family: Defining inline functions (as fast as macros)

 

Вернуться к Оглавлению


Copyright © 2010 rjaan as Andrey Rjavskov(Rzhavskov) <rjaan@yandex.ru> <arjavskov@gmail.com>