Table of Contents
مقدمه: Re-evaluating تابع Call Overhead
در برنامه نویسی C، هر تماس تابعی سربار را معرفی می کند: کامپایلر باید استدلال ها را بر روی پشته (یا آنها را در ثبت نام)، پرش به بدن تابع، اجرای کد، و سپس بازگشت.برای توابع کوچک و اغلب فراخوانی شده، این سربار می تواند به طور چشمگیری بر زمان اجرای، به ویژه در حلقه های بحرانی عملکرد غالب و یا عمیقا عملیات مدرن بهینه سازی تهاجمی، اما گاهی اوقات باید اشاره مستقیم به آن را به عنوان یک تابع یک تابع یک کاربر ارائه دهد:
مکانیسم پشت توابع Inline
در این میان، یک تابع خط با کلمه کلیدی (FLT:1) اعلام می شود که این دستور را به صورت خط داده نمی شود؛ این یک پیشنهاد است. کامپایلر ممکن است آن را برای توابعی که بسیار بزرگ، بازگشتی هستند، یا هنگامی که سطح بهینه سازی پایین است، در C99 و بعد از استانداردها، معانی (FLT:2 روشن شده است: تابع تعریف شده با تعریف (F:3) که اغلب در یک فایل یا چند بار دیگر به دست می رسد.
- تابع دارای لینک داخلی است؛ هر واحد ترجمه کپی خود را دریافت می کند.این امن ترین و قابل حمل ترین روش برای توابع کوچک کمک کننده تعریف شده در هدر است.
- [Extern inline] (C99): تعریف خط، بدن را برای inlining فراهم می کند، اما تعریف خارجی باید به طور جداگانه (معمولا در یک فایل .c) وجود داشته باشد.
- در خط بدون استاتیک یا extern: در C99، این شبیه به خط خارجی است؛ در C11، تعاریف خارجی تنها در صورتی مورد نیاز است که تابع به صورت عملی نباشد. برای اکثر موارد استفاده ترجیح می دهد.
بینش کلیدی: inlining یک ناهار رایگان نیست، کامپایلر تجزیه و تحلیل هزینه-benefit معامله-off: قرار دادن بدن تابع در هر سایت تماس افزایش اندازه کد (کد bloat)، که می تواند بهره وری حافظه دستورالعمل را کاهش دهد، بنابراین، در خط بهترین حالت برای توابع کوچک و اغلب به نام اختصاص داده می شود.
هنگامی که توابع Inline اکسل: استفاده از موارد و بهترین روش ها
عملیات ریاضی کوچک
توابعی که محاسبات ابتدایی را انجام می دهند – مانند محاسبه یک مربع، بستن یک ارزش یا تست یک نشانه – کاندیداهای اصلی هستند. سربار یک تماس تابع اغلب بزرگتر از خود عمل است.
static inline int clamp(int value, int low, int high) {
return (value < low) ? low : (value > high) ? high : value;
}
قابلیت های Accessor و Mutator در ساختارهای داده
الگوهای شی گرا در C اغلب از گیرنده ها و تنظیم کنندگان برای جمع آوری داده ها بدون درلینینگ استفاده می کنند، این توابع بی اهمیت سربار غیرضروری اضافه می کنند:
typedef struct {
int x, y;
} Point;
static inline int point_get_x(const Point *p) {
return p->x;
}
static inline void point_set_x(Point *p, int x) {
p->x = x;
}
سیستم های جاسازی شده و Real-Time Code
در محیط هایی با فضای پشته محدود و الزامات زمان بندی تعیین کننده، توابع خط نیاز به فشار / فریم های پشته را از بین می برند، کاهش هر دو تأخیر و استفاده از حافظه، با این حال، اندازه کد باید به دقت در میکروکنترلرهای حافظه آموزش دیده نظارت شود.
و هنگامی که [در برابر [از این] [از روی] [از روی [و] [در این [بر روی] [و] [از این [بر روی [و]] [به [و]] [از [و]] [به [و]]] [و [در [و] [و] [به [و]] [و [به [و] [و [به [و] [و [و [به [و]]] [و [و [و [و [در [از [به [به [و] [به [به [و] [و] [و] [به [به [و] [و] [و]]] [به [به [به [و [و [و] [به [و [به [به [و] [و] [از [و] [و] [و] [از [از [از [از [از [از [از [از [از [از [از [از [از [از [به]]] [از [به [این [و] [در [و] [در [و] [از [از [از [از [در [در [و] [و] [
- توابع بزرگ: در خط 100 + تابع خط در سایت های تماس متعدد خواهد شد دودویی و احتمالا عملکرد به دلیل فشار حافظه کش دستورالعمل.
- [[۱] [۱۰] [۱۰] [۱۰] [۱۰] [۱۰]] [۱۰]] [۱۰] [۳] [۱] [۱۰] [۱]] [۲]] [۲]] [۲]] [۲]] [۱۰] [۲] [۲]] [۲] [۲] [۲] [۲] [۲] [۲] [۲] [۲] [۲] [۲] [۲] [۲] [۲] [۲] [۲] [۲] [۲] [۲] [۲] [۲]]] [۲]] [۲] [۲] [۲] [۲]]] [۲]]]]]] [۲] [۲] [۲] [۲] [۲] [۲] [۲] [۲] [۲] [۲] [۲] [۲]] [۲] [۲] [۲] [۲] [۲] [۲] [۲] [۲]] [۲] [۲] [۲] [۲] [۲] [۲] [۲] [۲]]]] [۲] [۲]]] [۲] [۲
- [در این میان] [از این رو] با حلقه ها [از بین می رود: [[۱]] [۱۰] [۱۰] [۱] [۱۰] [۱]] [۱۰] [۱] [۱۰] [۱]] [۱۰] [۱۰] [۱]] [۱]] [۱۰] [۱]] [۱] [۱] [۱]] [۱] [۳] [۳] [۳] [۱] [۳]] [۳] [۳] [۳] [۳] [۱]]] [۱] [۱]]] [۱] [۳]] [۳] [۳] [۳]]]]] [۱]]]] [۳] [۳] [۳] [۳] [۳] [۳] [۳] [۳] [۳] [۳] [۳] [۳]] [۳] [۳] [۳] [۳] [۱] [۳] [۳] [۱]] [۱] [۱] [۳] [۳] [۳] [۳] [۱] [۳]]]] [۳] [۳]]]] [۳] [
- (به نام:0) اگر تابع نامیده شود، به طور ناگهانی به نام توابع (FLT 1)، اگر تابع نامیده می شود، فضای خالی است.
توابع خط ونوس ماکروs: یک مقایسه دقیق
قبل از اینکه کلمه کلیدی استاندارد بود، برنامه نویسان C از ماکروها ( برای دستیابی به "inlining" استفاده کردند، اما ماکروها جایگزین های متنی هستند، نه توابع با معایب جدی:
- ایمنی نوع: ماکروها انواع بدنام [FLT 11:] ماکرو چندین بار استدلال را ارزیابی می کنند، و منجر به عوارض جانبی خطرناک در هنگام استفاده با عبارات مانند می شود.
- [در این باره] [و] [از این رو] [از بین رفته]: [در زمان پیش پردازش، ماکروها در حال محو شدن هستند؛ اشکال زدایی نمی تواند به آنها وارد شود.
- [[۱] [۱۰] [۱] [۱] [۱] [۱] [۱]] [۱] [۱] [۱] [۱] [۱]] [۱]] [۱] [۱] [۱]] [۲]] [۱] [۱] [۱]] [۳] [۱] [۳] [۳] [۳] [۳] [۳] [۳] [۳] [۳] [۳] [۳] [۳] [۳] [۳] [۱] [۱] [۱] [۳] [۱] [۱] [۳] [۳] [۱] [۱] [۱] [۱] [۱] [۳] [۳] [۳] [۳] [۱] [۳] [۳] [۱] [۳] [۳] [۱] [۱] [۱] [۳] [۱] [۱] [۳] [۱] [۱] [۱] [۳] [۱] [۱] [۱] [۱] [۳] [۳] [۱] [۱] [۳] [۳] [۱] [۱] [۳] [۱]
- برخوردهای اسمی: گسترش ماکرو می تواند با متغیرهای محلی تداخل داشته باشد.
توابع خط بر تمام این مسائل غلبه می کنند: آنها توابع واقعی با چک کردن نوع، دامنه و ارزیابی استدلال ایمن جانبی هستند.آنها در سیستم نوع منظم شرکت می کنند و می توانند با اشکال زدایی شوند.تنها مزیت نظری ماکروها این است که آنها می توانند برای Type-gene [F:1] عملیات - اما C11 [F و D:14] که حتی کاهش فاصله 15:
{{FLT:1 ترجیح می دهد بر ماکروها برای هر منطق که متناسب با یک امضای تابع است، ماکروها را فقط برای ثابت های ساده یا توکن های گذشته است.
نمونه های عملی: توابع Inline در Action
مثال 1: Square (Al Ready Present)
static inline int square(int x) {
return x * x;
}
این کامپایلر احتمالا هیچ دستورالعمل تماسی را منتشر نخواهد کرد؛ کد به سادگی در هر سایت تماسی (FLT) 18 می شود.
مثال دوم: بررسی اینکه آیا یک شخصیت یک Digit است
static inline int is_digit(char c) {
return c >= '0' && c <= '9';
}
مثال 3: Fast Min/Max (Avocing Macros)
static inline int imax(int a, int b) {
return (a > b) ? a : b;
}
بر خلاف نسخه ماکرو، این ارزیابی (FLT 21) و (FLT 22) دقیقا یک بار، اجتناب از ریسک های دو برابر است.
مثال 4: Bit Operation (Unions یا Bytechangeping)
static inline uint16_t swap_bytes(uint16_t x) {
return (x << 8) | (x >> 8);
}
این کار به یک واحد (FLT:24) آموزش در ARM یا چرخش در x86 هنگامی که در خط لوله قرار دارد، انجام می شود.
بهینه سازی های Compiler و Inline Keyword
کلمه کلیدی تنها یک عامل در تصمیم گیری در حال نوشتن کامپایلر است. اکثر کامپایلرها دارای پرچم های خط فرمان هستند که تهاجمی بودن را کنترل می کنند:
- [[ویرایش] [[[۱]] [۱۰] [۱۰] [[۱]] [۱۰]] [[۳]] [۱۰] [۱] [۱۰] [۱]] [۱۰] [۱] [۱۰] [۱] [۱۰] [۱] [۳] [۱] [۳] [۳] [۳] [۳] پرچم [۲] می تواند به طور واضح فعال شود.
- ]MSVC: کلمه کلیدی در دسترس است، اما آن را تضمین نمی کند در خط زدن ( کامپایلر ممکن است هنوز برای برخی از توابع رد).
مثالی با ویژگی GCC:
static inline __attribute__((always_inline)) int triple(int x) {
return x * 3;
}
برای کد حیاتی عملکرد، توصیه می شود که مجمع تولید شده (به عنوان مثال، با GCC (FLT:33) یا را بررسی کنید تا تأیید کند که کامپایلرهای مدرن ممکن است در سطوح بهینه سازی بالا مشخص نشوند و برعکس ممکن است از 36LT برای عملکرد که باعث رشد کد بیش از حد می شود، بی اطلاع باشند.
احتمال بروز: Code Bloat و binary Size
توضیح هر تماس از یک تابع که در بسیاری از مکان ها استفاده می شود می تواند به طور قابل توجهی اندازه بخش متن را افزایش دهد.این به ویژه مشکل است برای:
- Libraries: توابع خط در هدرها به هر واحد ترجمه گسترش می یابند که شامل آنها، به طور بالقوه تکثیر اندازه کد.
- سیستم های فرو ریخته شده: فلش و رم محدود هستند.یک تابع 10 بایت استفاده شده در 1000 مکان تقریبا 10KB کد اضافه می کند.
- حافظه: کد بزرگتر می تواند باعث از دست رفتن حافظه بیشتر، کند شدن کل برنامه.
برای کاهش نفخ کد، از فقط برای عملکرد های کوچک (معمولا 1 تا 5 صورت) استفاده کنید تا مشخصات داغ را قبل از اینکه به طور کورکورانه در حال اجرا و اندازه دودویی باشد، شناسایی کنید.
توابع خط در سراسر استانداردهای C
[در این میان]، واژه [FLT 38] در و در معرفی شد و . C23] همان معنایی را با برخی از بهبودهای اضافی حفظ می کند.
اگر شما باید از کامپایلرهای پیش از C99 (که به طور فزاینده نادر است) پشتیبانی کنید، باید به ماکروها یا پیاده سازی های هدر-تنها خارجی برگردید، در غیر این صورت، را به عنوان یک جایگزین قابل حمل و نوع امن در نظر بگیرید.
نتیجه گیری: یک ابزار استراتژیک در ابزار مهندسی عملکرد
توابع خط یک ویژگی بالغ و به خوبی تعریف شده از زبان C است که، هنگامی که به طور منظم اعمال می شود، می تواند بهبود سرعت قابل اندازه گیری را با حذف تابع تماس سربار و فعال کردن بهینه سازی متقابل عملکرد متقابل عملکرد بالا از ماکروها در تقریبا هر زمینه مدرن است. کلید این است که استفاده خود را به توابع کوچک، گرم و تأیید نتیجه با پروفایل و بازرسی مناسب با کد های پایین - در یک کد پایین و پایین - در هر دو سطح پایین -
برای خواندن بیشتر، با ] مستندات در توابع خط و cppreference ورود به مشورت کنید برای تجزیه و تحلیل عملکرد در دنیای واقعی، این ACM Que [FLT5:5] بررسی جزئیات تجاری در جزئیات تجاری.