С Новым годом! Форум программистов, компьютерный форум, киберфорум
C для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.91/75: Рейтинг темы: голосов - 75, средняя оценка - 4.91
Модератор
Эксперт по электронике
8978 / 6744 / 921
Регистрация: 14.02.2011
Сообщений: 23,854

inline в Си

02.03.2019, 11:50. Показов 14412. Ответов 10
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
вопрос возник из этой темы Error: L6218E: Undefined symbol
сначала я предположил что у автора не подключен файл
но потом я увидел проект и понял что не прав
косяк именно в inline
если использовать static inline, то все в порядке
вопрос: Почему при использовании два и более раз inline функции линкер говорит что функция(имя) не определена?
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
02.03.2019, 11:50
Ответы с готовыми решениями:

GCC Inline Assembly перевести в Visual Studio Inline Assembler
Здравствуйте. Есть код на GCC Inline Assembly и его нужно перевести в Visual Studio Inline Assembler. Не работал с GCC Inline Assembly...

Inline функции - на сколько должна быть маленькая функция, чтоб она подошла под inline?
Здравствуйте. Знаю теорию, но не понимаю, на сколько должна быть маленькая функция, чтоб она подошла под inline ? Как...

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

10
725 / 224 / 73
Регистрация: 01.03.2011
Сообщений: 643
02.03.2019, 13:00
Цитата Сообщение от ValeryS Посмотреть сообщение
вопрос: Почему при использовании два и более раз inline функции линкер говорит что функция(имя) не определена?
код из той темы не скачивал, но достаточно 1го раза.
C
1
2
3
4
inline int inline_foo(int a, int b)
{
    return (a + b);
}
C
1
2
3
4
5
6
7
#include <stdio.h>
#include "inline.h"
 
int main(void) {
    printf("%d\n", inline_foo(1, 2));
    return 0;
}
inline без static или extern создает (точнее _может создать, если компилятор решит ее использовать) локальную относительно единицы трансляции "альтернативу" для внешнего объекта который должен существовать в другой единице трансляции. ЕЕ отсутствие - UB и большинство компиляторов даст ошибку.
static inline - явно установит linkage (как это нормально по-русски? связанность как-то криво...) функции в internal.
еще вариант добавить в .h декларацию
C
1
int inline_foo(int a, int b);
0
Модератор
Эксперт по электронике
8978 / 6744 / 921
Регистрация: 14.02.2011
Сообщений: 23,854
02.03.2019, 13:48  [ТС]
Цитата Сообщение от prik Посмотреть сообщение
inline без static или extern создает (точнее _может создать, если компилятор решит ее использовать) локальную относительно единицы трансляции "альтернативу" для внешнего объекта который должен существовать в другой единице трансляции. ЕЕ отсутствие - UB и большинство компиляторов даст ошибку.
можешь как нибудь попроще
Цитата Сообщение от prik Посмотреть сообщение
C
1
2
3
4
5
6
7
#include <stdio.h>
#include "inline.h"
 
int main(void) {
    printf("%d\n", inline_foo(1, 2));
    return 0;
}
вот здесь одна единица трансляции main
и никаких внешних нет
0
725 / 224 / 73
Регистрация: 01.03.2011
Сообщений: 643
02.03.2019, 14:05
Цитата Сообщение от ValeryS Посмотреть сообщение
можешь как нибудь попроще
Наверное да. Смущает понятие linkage или что-то другое? Я к тому, с какого момента начинать переформулировать.
Цитата Сообщение от ValeryS Посмотреть сообщение
вот здесь одна единица трансляции main
и никаких внешних нет
по тому с исходным вариантом inline.h без static или доп декларации inline_foo() оно и должно выдавать ошибку.
0
Модератор
Эксперт по электронике
8978 / 6744 / 921
Регистрация: 14.02.2011
Сообщений: 23,854
02.03.2019, 14:21  [ТС]
Цитата Сообщение от prik Посмотреть сообщение
Смущает понятие linkage или что-то другое?
пока не готов сказать
никогда с этим не сталкивался, поскольку inline в си не пользовался
вот такой код
C
1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
/// #include "inline.h"
 inline int inline_foo(int a, int b)
{
    return (a + b);
}
int main(void) {
    printf("%d\n", inline_foo(1, 2));
     printf("%d\n", inline_foo(1, 2));
 
    return 0;
}
тоже вызывают ошибку
хотя единица трансляции точно одна
в общем поэкспериментирую и скажу
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
02.03.2019, 15:07
Вообще в разных диалектах Си ключевое слово inline трактуется по-разному: http://www.greenend.org.uk/rjk/tech/inline.html, причём отлично от Си++
Вероятно, в вашем случае речь идёт о C99

Добавлено через 6 минут
В таком случае следует добавить в компиляцию ещё один модуль, в котором тело функции объявлено без inline

Логика этого хозяйства примерно такая, что в хидер помещается функция с телом и inline'ом, а в библиотеку - функция с телом, но без inline. Описание из хидера трактуется как "это описание внешней фукнции, но если компилятор готов выполнять inline, то вот вам копия тела функции, оригинал реализован где-то в другом месте". В итоге компилятор в режиме без inline трактует такую конструкцию как "extern inline функция", а в режиме с inline - грубо говоря, как "static inline функция"

В Си++11 есть аналогичная конструкция - это extern template
3
725 / 224 / 73
Регистрация: 01.03.2011
Сообщений: 643
02.03.2019, 22:24
Осталось объяснить почему так. Я постараюсь писать как-можно проще, но не для полных "чайников" и опущу аспекты касающиеся только переменных. ТС может читать со связывания.
Зайдем издалека
Область видимости
Обычно под этим понятием рассматривают глобальные и локальные переменные. В контексте темы областью видимости, если не указанно явно, следует считать "единицу трансляции". Локальная - текущий файл, глобальная - какие-то другие неподключаемые через #include файлы.

Что такое декларация(в русских книжках тут иногда говорят "объявление", но мне не нравится) и определение функции
Декларация задает как минимум имя функции и тип возвращаемого значения.
C
1
void foo();
типы и имена ее параметров.
C
1
void foo(int); void foo(int bar);
Последний вариант, с именами параметров, называется протипом функции.
Деклараций одной и той же функции может быть много, но в пределах одной области видимости они не должны противоречить друг другу.
Определение же ф-ции, это среди прочего "выделение памяти" под тело функции. Т.е это, то, что мы пишем с фигурными скобочками.
C
1
void foo(int bar){bar++;}
Где можно поместить декларацию функции
Если не делать разницы между .c и .h файлами (ее и на самом деле нет). То варианта только два:
1. В глобальном пространстве файла.
2. В блоке {}

Где можно поместить определение функции
Только в глобальном пространстве файла. (Нестандартные расширения языка типа nested functions в gcc мы не рассматриваем)

Что такое связывание (linkage)
Это процесс (этап компиляции), позволяющий установить, что несколько разных деклараций ссылаются на одно и то же определение.
Существует 2 типа связей (на самом деле 3, но none для функций не применимо):
1. внешнее (external) - все такие декларации, даже распложенные в разных .c файлах ссылаются на одну и ту же функцию.
2. внутренне (internal) - в рамках одного .c файла.

Как задается тип связи.
Для ф-ций существует 2 варианта
1. static - внутренне связь
1.1 Попытка переопределить предыдущую extern декларацию - ошибка.
1.2 Можно использовать только в глобальном пространстве .c файла (т.е. внутри блока функцию можно декларировать только как extern)
2. extern - внешняя связь.
2.1 Выигрывает static: Если в области видимости текущей декларации есть более ранняя декларация с явным static - то связывание останется внутренним, ошибки не будет.
2.2. Если в области видимости текущей декларации нет более ранней, или есть, но без явного указания связывания - то связывание будет внешним.
Если функция декларирована без явного указания класса - связывание внешнее.

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

главное (откуда баг)
C
1
inline void foo(int bar);
Если в файле есть только такая декларация без явного указания на тип связывания - это называется "inline декларация" и она не задает тип связи по умолчанию, как это было бы сделано для void foo(int bar); Эта конструкция создает альтернативу для расположенной в другом файле декларации. Т.е. мы обязанны либо иметь определение без inline для такой функции в текущем файле, либо использовать extern.

Не по теме:

Прошу прощения за сумбурность - отвлекался несколько раз в процессе написания сего опуса.

1
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
03.03.2019, 13:12
Лучший ответ Сообщение было отмечено ValeryS как решение

Решение

Цитата Сообщение от prik Посмотреть сообщение
inline
Это просьба компилятору сделать вызов функции как можно более быстрым
Стандартное пояснение из учебников. Сделанное без понимания, что на самом деле означает слово inline. В разных языках/диалектах слово inline означает разные свойства. Помимо "просьбы сделать вызов как можно более быстрым" есть и другие свойства. Их в учебниках как правило не озвучивают, не озвучил и ты

Цитата Сообщение от prik Посмотреть сообщение
Т.е. мы обязанны либо иметь определение без inline для такой функции в текущем файле, либо использовать extern
В изначальном примере была совсем другая конструкция - definition со словом inline, а вовсе не declaration

А если посмотреть на первое из двух "либо" (либо иметь определение без inline для такой функции в текущем файле), то это, строго говоря, не верно. Если в текущем файле будет определение функции без inline, то оно попросту отменит декларацию с inline'ом, а вовсе не дополнит, как могло бы показаться на первый взгляд

C
/* Файл t1.c */
 
#if 1
 
/* Это то, о чём шла речь в изначально озвученной проблеме */
inline int inline_foo (int a, int b)
{
    return (a + b);
}
 
#else
 
/* Это аналог первого "либо" из твоей трактовки. Но он совсем не равнозначен
 * вышеидущему варианту. Он равнозначен варианту, когда inline декларация
 * попросту отсутствует */
inline int inline_foo (int a, int b);
 
int inline_foo (int a, int b)
{
    return (a + b);
}
 
#endif
 
int main (void)
{
  return inline_foo (1, 2);
}
C
/* Файл t2.c */
 
/* Это вспомогательная функция, при помощи которой
 * мы проверяем корректность кода из первого файла */
int inline_foo (int a, int b)
{
    return (a + b);
}
При запуске я использую опцию -fno-inline, по которой в gcc отключается построение inline-подстановок функций. Чтобы гарантированно настроить один из возможных режимов (и не заморачиваться с телом функции большого размера) и чтобы в конечном итоге не зависеть от поведения конкретной версии компилятора

Code
$ gcc-7.3.0 t1.c t2.c -std=c99 -fno-inline
<ok>
Теперь заменим "#if 1" на "#if 0"

Code
$ gcc-7.3.0 t1.c t2.c -std=c99 -fno-inline
/tmp/cchQK5rf.o: In function `inline_foo':
t2.c:(.text+0x0): multiple definition of `inline_foo'
/tmp/ccpDJXSE.o:t1.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
Т.е. твоё первое "либо" оказывается некорректным

Добавлено через 54 минуты
Вышеидущий пример вместо опции "-fno-inline" можно скомпилировать с "-O3 -finline". Чтобы быть уверенным в том, что всё остаётся так же, независимо от того, выполняет компилятор inline-подстановки, или нет
1
725 / 224 / 73
Регистрация: 01.03.2011
Сообщений: 643
03.03.2019, 13:45
Цитата Сообщение от Evg Посмотреть сообщение
Т.е. твоё первое "либо" оказывается некорректны
Спасибо за замечание. Перечитал, правильно будет сформулировать так:
Обязаны определить эту функцию (inline без указания типа связи)в текущем файле не меняя ее связанность.
Такая функция не создаст "outline" (как правильно обозвать альтернативу inline???) версию, но создаст внешнюю связь с "outline" версией существующей где-то в другом файле.
Цитата Сообщение от Evg Посмотреть сообщение
Их в учебниках как правило не озвучивают, не озвучил и ты
Скорость - цель. Возможность иметь разный код в разных единицах трансляции под одним именем - побочный эффект. Других свойств действительно не знаю, но буду рад услышать.
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
03.03.2019, 14:14
Цитата Сообщение от prik Посмотреть сообщение
Обязаны определить эту функцию (inline без указания типа связи)в текущем файле не меняя ее связанность.
Такая функция не создаст "outline" (как правильно обозвать альтернативу inline???) версию, но создаст внешнюю связь с "outline" версией существующей где-то в другом файле.
Честно говоря, нифига не понял

Цитата Сообщение от prik Посмотреть сообщение
Скорость - цель
Скорость - это последняя цель

Цитата Сообщение от prik Посмотреть сообщение
Возможность иметь разный код в разных единицах трансляции под одним именем - побочный эффект
Это как раз-таки основное прямое назначение. Для него было бы логичным назначить другое ключевое слово. Но в силу каких-то исторических причин задействовали ранее существующее ключевое слово. Основное назначение этого ключевого слова - это именно наделить функции дополнительными свойствами, которые ты обозвал "побочным эффектом". Указание компилятору "выполнять inline-подстановку" уже больше лет 20-30 как неактуально, т.к. компиляторы давно сами решают, нужно или не нужно строить inline-подстановку, им не нужны никакие "просьбы сделать вызов функции как можно более быстрым"

Упоминание о таких просьбах можно встретить в учебниках 70-80-х годов, когда действительно такая просьба имела место быть - из-за маленького количества памяти компиляторы были слабенькими, а потому многих вещей не могли делать без дополнительных подсказок. Потом памяти стало больше, компиляторы поумнели, такая надобность отвалилась. В первом официально стандарте Си вообще не было никакого inline'а. В языке C++ задействовали ключевое слово inline, но под другой смысл, а во многих учебниках по прежнему писали старую трактовку inline'а, потому как большинство афторов учебников и сами толком не знали, зачем оно нужно (а срубить денег хотелось). Я совсем не удивлюсь, если окажется, что и в наше время приличная доля преподавателей в школах/институтах до сих пор не знают истинную семантику слова inline в современных стандартах языков Си и Си++

Цитата Сообщение от prik Посмотреть сообщение
Других свойств действительно не знаю, но буду рад услышать
Error: L6218E: Undefined symbol
0
725 / 224 / 73
Регистрация: 01.03.2011
Сообщений: 643
03.03.2019, 15:40
Цитата Сообщение от Evg Посмотреть сообщение
Это как раз-таки основное прямое назначение.
Тем не менее, официальная цель не менялась с момента появления - c99. В c11 ничего в этом плане ничего нового не принес. Именно поэтому везде озвучивается она...
Цитата Сообщение от Evg Посмотреть сообщение
Сообщение от prik Посмотреть сообщение
Других свойств действительно не знаю, но буду рад услышать
По ссылке ничего нет.Если вам известно, что кроме подстановки и linkage, то тезисно (можно просто ключевыми словами) тут, если несложно.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
03.03.2019, 15:40
Помогаю со студенческими работами здесь

inline
В хедере определён класс со static-методами, в исходнике реализация этих методов. Один из методов определяется с ключевым словом inline....

Inline li
Доброго времени суток, не подскажите почему li не ставятся в inline? &lt;div class=&quot;card_hover&quot;&gt; &lt;ul...

inline
Занимаюсь программированием на С++ больше года. Но к сожалению не имею хорошего представления о том как устроены компиляторы. В частности...

#define VS inline
Что работает быстрее: #define SQR(x) x*x void Func() { for(int i = 0; i &lt; 10; ++i) { cout &lt;&lt; SQR(i) &lt;&lt; endl; ...

inline - функции
Стоит-ли добавлять префикс inline ко всем функциям, состоящим из 1-2 строк?


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
11
Ответ Создать тему
Новые блоги и статьи
Расчёт токов в цепи постоянного тока
igorrr37 05.01.2026
/ * Дана цепь постоянного тока с сопротивлениями и напряжениями. Надо найти токи в ветвях. Программа составляет систему уравнений по 1 и 2 законам Кирхгофа и решает её. Последовательность действий:. . .
Новый CodeBlocs. Версия 25.03
palva 04.01.2026
Оказывается, недавно вышла новая версия CodeBlocks за номером 25. 03. Когда-то давно я возился с только что вышедшей тогда версией 20. 03. С тех пор я давно снёс всё с компьютера и забыл. Теперь. . .
Модель микоризы: классовый агентный подход
anaschu 02.01.2026
Раньше это было два гриба и бактерия. Теперь три гриба, растение. И на уровне агентов добавится между грибами или бактериями взаимодействий. До того я пробовал подход через многомерные массивы,. . .
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Programma_Boinc 28.12.2025
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост. Налог на собак: https:/ / **********/ gallery/ V06K53e Финансовый отчет в Excel: https:/ / **********/ gallery/ bKBkQFf Пост отсюда. . .
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Нашел на реддите интересную статью под названием Anyone know where to get a free Desktop or Laptop? Ниже её машинный перевод. После долгих разбирательств я наконец-то вернула себе. . .
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод Нашел на реддите интересную статью под названием The Thinkpad X220 Tablet is the best budget school laptop period . Ниже её машинный перевод. Thinkpad X220 Tablet —. . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru