Я понимаю, что inline
само по себе это предложение для компилятора, и по своему усмотрению он может или не может встроить функцию, а также будет создавать объектный код с возможностью связывания.
Я думаю, что это static inline
делает то же самое (может или не может быть встроенным), но не будет создавать связываемый объектный код при встроенном (поскольку ни один другой модуль не может ссылаться на него).
Где extern inline
вписывается в картину?
Предположу , я хочу , чтобы заменить препроцессор макрос инлайн функции и требую , чтобы эта функция получает встраиваемую (например, потому что он использует __FILE__
и __LINE__
макросы , которые должны решить для вызывающего абонента , но это не называется функция). То есть я хочу видеть ошибку компилятора или компоновщика, если функция не встроена. Это делает extern inline
? (Я полагаю, что в противном случае нет другого способа добиться такого поведения, кроме как придерживаться макроса.)
Есть ли различия между C ++ и C?
Есть ли различия между разными поставщиками и версиями компиляторов?
источник
extern inline
подчиняется правилу одного определения, и это определение. Но если эвристика оптимизации, определяемая реализацией, следует рекомендации использоватьinline
ключевое слово в качестве предложения, что «вызовы функции должны быть как можно более быстрыми» (ISO 9899: 1999 §6.7.4 (5),extern inline
считаетсяЯ считаю, что вы неправильно поняли __FILE__ и __LINE__ на основании этого утверждения:
Есть несколько этапов компиляции, и предварительная обработка - первая. __FILE__ и __LINE__ заменяются на этом этапе. Итак, к тому времени, когда компилятор сможет рассмотреть функцию для встраивания, они уже заменены.
источник
Похоже, вы пытаетесь написать что-то вроде этого:
inline void printLocation() { cout <<"You're at " __FILE__ ", line number" __LINE__; } { ... printLocation(); ... printLocation(); ... printLocation();
и надеемся, что каждый раз вы будете получать разные значения. Как говорит Дон, вы этого не сделаете, потому что __FILE__ и __LINE__ реализуются препроцессором, а встроенные - компилятором. Итак, откуда бы вы ни вызывали printLocation, вы получите тот же результат.
Только способ , которым Вы можете получить эту работу, чтобы сделать printLocation макрос. (Да, я знаю...)
#define PRINT_LOCATION {cout <<"You're at " __FILE__ ", line number" __LINE__} ... PRINT_LOCATION; ... PRINT_LOCATION; ...
источник
Ситуация с inline, static inline и extern inline сложна, не в последнюю очередь потому, что gcc и C99 определяют несколько разные значения для своего поведения (и, предположительно, C ++ тоже). Вы можете найти полезную и подробную информацию о том, что они делают в C здесь .
источник
Здесь вы выбираете макросы, а не встроенные функции. Редкий случай, когда макросы преобладают над встроенными функциями. Попробуйте следующее: я написал этот код "МАКРОМАГИИ", и он должен работать! Протестировано на gcc / g ++ Ubuntu 10.04
//(c) 2012 enthusiasticgeek (LOGGING example for StackOverflow) #ifdef __cplusplus #include <cstdio> #include <cstring> #else #include <stdio.h> #include <string.h> #endif //=========== MACRO MAGIC BEGINS ============ //Trim full file path #define __SFILE__ (strrchr(__FILE__,'/') ? strrchr(__FILE__,'/')+1 : __FILE__ ) #define STRINGIFY_N(x) #x #define TOSTRING_N(x) STRINGIFY_N(x) #define _LINE (TOSTRING_N(__LINE__)) #define LOG(x, s...) printf("(%s:%s:%s)" x "\n" , __SFILE__, __func__, _LINE, ## s); //=========== MACRO MAGIC ENDS ============ int main (int argc, char** argv) { LOG("Greetings StackOverflow! - from enthusiasticgeek\n"); return 0; }
Для нескольких файлов определите эти макросы в отдельном файле заголовка, включая их в каждом файле c / cc / cxx / cpp. По возможности предпочитайте встроенные функции или константные идентификаторы (в зависимости от случая) макросам.
источник
Вместо ответа «что он делает?» Я отвечаю: «как мне заставить его делать то, что я хочу?» Существует 5 видов встраивания, все из которых доступны в GNU C89, стандартном C99 и C ++:
всегда в строке, если не указан адрес
Добавьте
__attribute__((always_inline))
к любому объявлению, а затем используйте один из следующих случаев, чтобы обработать возможность его адреса.Вы, вероятно, никогда не должны использовать это, если вам не нужна его семантика (например, чтобы влиять на сборку определенным образом или использовать
alloca
). Компилятор обычно лучше вас знает, стоит ли оно того.встроенный и испускает слабый символ (например, C ++, он же «просто заставь его работать»)
__attribute__((weak)) void foo(void); inline void foo(void) { ... }
Обратите внимание, что при этом остается множество копий одного и того же кода, и компоновщик выбирает одну произвольно.
встроенный, но никогда не испускать никаких символов (оставляя внешние ссылки)
__attribute__((gnu_inline)) extern inline void foo(void) { ... }
испускать всегда (для одного TU, чтобы разрешить предыдущее)
Подсказанная версия испускает слабый символ в C ++, но сильный символ на любом диалекте C:
void foo(void); inline void foo(void) { ... }
Или вы можете сделать это без подсказки, которая испускает сильный символ на обоих языках:
void foo(void) { ... }
Как правило, вы знаете, на каком языке находится ваш ЕП, когда предоставляете определения, и, вероятно, не нуждаетесь во встраивании.
inline и emit в каждом TU
static inline void foo(void) { ... }
Для всех из них, кроме
static
одного, вы можете добавитьvoid foo(void)
объявление выше. Это помогает с «лучшей практикой» писать чистые заголовки, а затем#include
вставлять отдельный файл со встроенными определениями. Затем, если вы используете встроенные строки в стиле C,#define
некоторые макросы по- разному в одном выделенном TU для предоставления автономных определений.Не забывайте, может
extern "C"
ли заголовок использоваться как в C, так и в C ++!источник
nm
эквивалент.