2014-02-14 2 views
0

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

В-файле, определяется статическая переменная и встраиваемая функция упрощается следующим образом:

static int ply; 

inline int WTM(){return ply;} 

и функция вызывается в какой-либо другой cpp файл, который включает эту головку.

cout << ply << " " << WTM(); 

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

Выходной сигнал 0 1;

Я проверил весь файл, и оба ply и WTM() просто имеют это единственное определение.

После этого я изменил код на следующее:

static int ply; 

static inline int WTM(){return ply;} 

Два значения стали одинаковыми.

Мой компилятор: g++ (GCC) 4.4.7 с настройками по умолчанию.

Я искал об этом явлении и добраться до этого два звена: Difference between an inline function and static inline function и http://gcc.gnu.org/onlinedocs/gcc/Inline.html , но до сих пор не понимаю, почему это могло произойти (особенно, почему они могут иметь разные значения в первой ситуации). Интересно, может ли кто-нибудь сказать мне, как компилятор расширит эти два фрагмента кода (я пробовал использовать -E, но, похоже, он не работает над встроенной функцией).

+0

Я не понимаю, откуда приходит «1». Независимо от области действия, это должно быть 0. – starmole

+0

@starmole I * guess * есть назначение в одной единицы перевода. –

+0

Да, на самом деле есть много других заданий. –

ответ

5

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

Что отличает вас от того, что функция объявлена ​​static, то она будет определена в каждом модуле перевода так же, как и переменная, и, таким образом, получить доступ к переменной только для этой единицы перевода.

+0

Не является ли также открытым вопрос о том, какая копия функции была связана? В каждом объектном файле будет определена эта функция, поэтому я думаю, что возвращаемая переменная 'ply' будет той, что была от связанной функции. – jthill

+0

спасибо. Я попытался напечатать их адреса, и у них есть разные адреса. –

-1

с помощью ссылки What's the difference between “static” and “static inline” function?:

inline инструктирует компилятор пытаться вставлять содержимое функции в коде вызова вместо выполнения фактического вызова.

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

Однако это только «подсказка», и компилятор может ее игнорировать, и большинство компиляторов попытаются «inline», даже если ключевое слово не используется, как часть оптимизаций, где это возможно.

, например:

static int Inc(int i) {return i+1}; 
.... // some code 
int i; 
.... // some more code 
for (i=0; i<999999; i = Inc(i)) {/*do something here*/}; 

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

int i; 
.... 
for (i=0; i<999999; i = i+1) { /* do something here */}; 

Пропуск фактического вызова функции и возврата

Очевидно, что это пример, чтобы показать точку, а не реальный кусок кода ,

static относится к сфере применения. В C это означает, что функция/переменная может использоваться только в пределах одной единицы перевода.

+0

Использование 'inline' для функции - это всего лишь * предложение *, что компилятор * может * встроить код, если он так выбирает. Это не требование. –

+1

Да, но inline также позволяет включить одну и ту же функцию в несколько единиц перевода с нарушением odr. –

0

Ваше первое использование встроенной функции без статики - это неопределенное поведение.

Standard 3.2.6

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

- каждое определение D должно состоять из одной и той же последовательности токенов; и

- в каждом определении D, соответствующие имена, смотрели вверх в соответствии с 3.4, относятся к сущности, определенной в пределах определения D, или будет относиться к одной и той же сущности,

- .. .

Если определения D удовлетворяют всем этим требованиям, то программа должна вести себя, как если бы было одно определение D. Если определения D не удовлетворяют этим требованиям, то поведение не определено.

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

0

Существует также еще одно объяснение этого:

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

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

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

Inline функции - это оптимизация, и она действительно «работает» только в оптимизации компиляции. Если вы не используете -O, никакой функции действительно нет inline.

и для static inline function:

Когда функция является одновременно inline и static,

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

В этом случае compiler фактически не выходной ассемблерный код для функции, если не указан параметр -fkeep-inline-functions.

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

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

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