Следует ли использовать ключевое слово inline в КАЖДОМ объявлении?

Как компилятор решает, следует ли рассматривать функцию как встроенную или нет?

В отличие от компоновки, не существует такого понятия, как «встроенные» конфликты (объявления с одним и тем же именем могут быть встроенными или нет).

Например, несколько объявлений функций могут быть встроенными или нет, например:

inline static void test(); // declaration with inline

int main()
{
    extern void test(); // declaration without inline.
    test();
}  

static void test() // definition does not have inline
{
}

or

static void test(); // declaration without inline

int main()
{
    test();
}  

inline static void test() // but definition has inline!
{
}

В каждом случае встраивается ли функция test()?

Мой реальный вопрос: как компилятор обнаруживает, что функция должна быть встроена? Проверяет ли он, содержит ли самое последнее объявление встроенное ключевое слово, или проверяет, содержит ли определение встроенное ключевое слово или нет?

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

(Сначала я думал, что должно быть «правило», которое предписывает, что после объявления встроенной функции каждое объявление с тем же именем также должно быть встроенным.)


РЕДАКТИРОВАТЬ: я в основном спрашиваю, как компилятор решает неоднозначность нескольких объявлений с одинаковыми именами, только некоторые из которых содержат встроенное ключевое слово.

inline static void test() // definition with inline keyword
{
}

int main()
{
    extern void test(); // declaration without inline
    test(); // Does compiler consider inlining or not?
}

person SHH    schedule 16.11.2011    source источник
comment
Просто не беспокойтесь об этом. Оставьте inline вне своего кода и позвольте компилятору побеспокоиться.   -  person pmg    schedule 17.11.2011
comment
Прочитайте это: drdobbs.com/184403879#   -  person Fred Larson    schedule 17.11.2011
comment
Компиляторы могут встраивать то, что вы не пометили как встроенное, и часто не встраивают то, что вы им сказали. Позвольте компилятору сделать вызов, просто оставьте его как подсказку для людей, если вы почувствуете необходимость (смотрите, эта функция эффективна, потому что ее оптимизируют).   -  person sehe    schedule 17.11.2011
comment
Я не спрашиваю, будут ли компиляторы встраивать это или нет. Я спрашиваю, узнают ли компиляторы о моем намерении встроить в такие неоднозначные ситуации. Эта двусмысленность должна быть определена где-то в стандарте, но я не могу ее найти.   -  person SHH    schedule 17.11.2011
comment
Соответствующей частью стандарта является 6.7.4/6. На практике приличный компилятор не очень заинтересован в вашем намерении встроить, он будет встраивать или нет в соответствии со своими собственными правилами, которые, вполне возможно, не зависят от того, помечена ли функция как встроенная или нет. Значимые эффекты пометки встроенной функции не связаны с встраиванием. Кстати, в вашем первом фрагменте кода test имеет внутреннюю связь в первом объявлении и внешнюю ссылку во втором объявлении, которое игнорируется 6.2.2/4, идентификатор по-прежнему имеет внутреннюю связь.   -  person Steve Jessop    schedule 17.11.2011
comment
@Steve Jessop Мне интересно, что говорит об этом официальный стандарт. Я могу только посмотреть черновик, и в нем упоминается только то, что во всех объявлениях есть ключевое слово inline без extern или static. Согласно greenend.org.uk/rjk/2003/03/inline. html, я думаю, что в официальном стандарте (не в черновике) упоминается случай, когда функция, в которой хотя бы в одном объявлении упоминается встроенный, но где в каком-то объявлении не упоминается встроенный или упоминается внешний. Может быть, мне нужно купить стандарт C99 и взглянуть на него.   -  person SHH    schedule 17.11.2011
comment
Я использую n1256, который находится в свободном доступе и является последним опубликованным проектом TC3. В нем обсуждаются случаи, когда одни объявления помечены встроенными, а другие нет. В нем также обсуждается extern - объявление встроенной функции с extern в области файла (но не в области функции, как в вашем первом примере) обеспечивает внешнее определение. В противном случае нет внешнего определения.   -  person Steve Jessop    schedule 17.11.2011
comment
Я смотрю на n1256, и он указывает только два случая: 1. внешняя связь с каждым объявлением, имеющим встроенный без внешнего: создает встроенное определение. 2. внешняя связь с extern или только некоторыми встроенными ключевыми словами: создает внешнее определение. Но в нем ничего конкретного не говорится о статических встроенных функциях (упоминается одна строка: любая функция с внутренней связью может быть встроенной функцией. Что насчет случая, когда определена статическая функция, и только статическое объявление имеет встроенное ключевое слово? (мой пример №1 сверху).   -  person SHH    schedule 17.11.2011
comment
Но я начинаю верить, что если какое-либо одно объявление имеет встроенное значение (определение или нет), то компилятор будет смотреть на функцию, как если бы она была объявлена ​​встроенной.   -  person SHH    schedule 17.11.2011


Ответы (1)


Мой реальный вопрос: как компилятор обнаруживает, что функция должна быть встроена? Проверяет ли он, содержит ли самое последнее объявление встроенное ключевое слово, или проверяет, содержит ли определение встроенное ключевое слово или нет?

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

Ключевое слово inline предназначено для помощи, но, как и ключевое слово register, оно мало что дает при создании кода. Вместо этого inline просто означает «не жалуйтесь, если вы видите это определение более одного раза (потому что я вставляю его в заголовочный файл)».

Это «не жалуйтесь» — вот почему ваш код не жалуется, хотя, вероятно, должен.

Если вы собираетесь использовать ключевое слово, не помещайте его в предварительную декларацию, а делайте поместите его в определение (и делайте > поместить определение в шапку):

void test();

/* ... other declarations ... */

/* (in the same file) */

inline void test() { printf("inlined!\n"; }

На самом деле для этого есть причина: вы можете не захотеть загромождать свои объявления реализациями.

person Max Lybbert    schedule 16.11.2011
comment
Правило №1: если тело функции находится в заголовочном файле. Это правило не имеет абсолютно никакого смысла. Разве что-то в заголовочном файле просто не вставлено в исходный код? - person SHH; 17.11.2011
comment
@SHH Я не думаю, что современные компиляторы выполняют оптимизацию времени компоновки требуется, чтобы функция была определена в заголовке, но раньше компилятор должен был иметь возможность видеть тело функции в месте вызова, чтобы выполнить встраивание - person Praetorian; 17.11.2011
comment
@SHH: да, файлы заголовков содержимого сбрасываются в любой файл .c, в который они включены, а затем файлы .c превращаются в объектный код. Размещение тела функции в заголовке означает, что тело функции доступно компилятору во время его фактической компиляции и, следовательно, доступно для встраивания. В качестве альтернативы можно было бы поместить тело в файл .c, скомпилировать его в файл .o и не иметь тело функции во время компиляции компилятора (а вместо этого иметь файл .o для ссылка на то, когда компоновщик связывается). - person Max Lybbert; 17.11.2011
comment
Praetorian упомянул оптимизацию времени компоновки, которую я не учел, когда писал вопрос. Но да, компоновщики теперь достаточно сложны, чтобы встраивать ваш код даже без прямого доступа к исходному коду. - person Max Lybbert; 17.11.2011