मैं एक फ़ंक्शन को इनलाइन नहीं करने के लिए कैसे कह सकता हूं?


126

कहो कि मेरे पास स्रोत फ़ाइल में यह छोटा कार्य है

static void foo() {}

और मैं अपने बाइनरी के एक अनुकूलित संस्करण का निर्माण करता हूं, फिर भी मैं यह फ़ंक्शन इनबिल्ड (अनुकूलन उद्देश्यों के लिए) नहीं चाहता हूं। वहाँ एक मैक्रो मैं एक स्रोत कोड में tolining रोकने के लिए जोड़ सकते हैं?


इस सवाल के लिए धन्यवाद! जब मैं एक समारोह में नहीं दिखा, तो मैं ऑप्रोफाइल के साथ प्रोफाइलिंग कर रहा था।
साइमन ए। युगस्टर

जवाबों:


149

आप gcc-specific noinlineविशेषता चाहते हैं ।

यह फ़ंक्शन विशेषता एक फ़ंक्शन को इनलाइनिंग के लिए विचार करने से रोकती है। यदि फ़ंक्शन के साइड-इफेक्ट्स नहीं हैं, तो इनलाइनिंग के अलावा अन्य अनुकूलन हैं जो फ़ंक्शन कॉल को अनुकूलित करने का कारण बनता है, हालांकि फ़ंक्शन कॉल लाइव है। इस तरह की कॉलों को दूर रखने के लिए, पुट किया जाना चाहिए asm ("");

इसे इस तरह उपयोग करें:

void __attribute__ ((noinline)) foo() 
{
  ...
}

32
आर्क लिनक्स पर 4.4.3 gcc का उपयोग करते हुए, मुझे ऊपर बताई गई विशेषता के साथ एक सिंटैक्स त्रुटि मिलती है। यह सही ढंग से काम करता है जब यह कार्य (जैसे, विशेषता ((noinline))) शून्य foo () {}) से पहले करता है
mrkj

2
Arduino भी चाहता था कि इसे समारोह से पहले रखा जाए।
पीटर एन लुईस

2
विशेषता सिंटैक्स को ठीक करने के लिए संपादित किया गया।
क्क्सप्लसोन

1
एएसएम ("") निर्माण वास्तव में काफी क्रॉस-प्लेटफॉर्म है और काम हो गया है। मैंने इसे x86 लिनक्स के लिए किया था और इसने पावरपीसी एआईएक्स पर निर्माण समस्या का कारण नहीं बनाया। इस उपयोगी सुझाव के लिए धन्यवाद!
मार्टी

1
जिस दृष्टिकोण को हर जगह कोड परिवर्तन की आवश्यकता होती है, उसे यथोचित स्वीकार्य उत्तर नहीं माना जा सकता है।
अंजीह

31

GCC में एक स्विच होता है जिसे कॉल किया जाता है

-fno-inline-small-functions

इसलिए gcc का प्रयोग करते समय इसका उपयोग करें। लेकिन साइड इफेक्ट यह है कि अन्य सभी छोटे कार्य भी गैर-अंतर्निर्मित हैं।


संकलक स्तर पर काम नहीं किया। Gcc 5.2.1 20150902 (Red Hat 5.2.1-2) का उपयोग कर रहा था
जॉन ग्रीन

या तो वर्तमान जीसीसी 6.4 टूट गया है, या यह और सरल -fno-inlineबिल्कुल काम नहीं करता है। gdbअभी भी कदम-पर-तरीकों में प्रवेश करता है। कुछ टूट गया है, और मुझे संदेह है कि यह है gdb
अजेह

यह केवल निर्दिष्ट फ़ंक्शन के लिए ही नहीं, सभी के लिए इनलाइन ऑप्टिमाइज़ेशन को बंद कर देगा।
जहाँ 23

@ajeh इनलाइन कार्यों का मतलब यह नहीं है कि उन्हें सामान्य रूप से कहा जाता है, है ना?
मेलेबियस

21

ऐसा करने का एक पोर्टेबल तरीका सूचक के माध्यम से फ़ंक्शन को कॉल करना है:

void (*foo_ptr)() = foo;
foo_ptr();

हालांकि यह शाखा को अलग-अलग निर्देश देता है, जो आपका लक्ष्य नहीं हो सकता है। जो एक अच्छा बिंदु लाता है: यहां आपका लक्ष्य क्या है ?


2
यदि सूचक फ़ाइल दायरे में परिभाषित किया गया है, और स्थिर नहीं है, तो इसे संकलक के बाद से काम करना चाहिए, फिर यह मान नहीं सकता कि उपयोग के समय इसका प्रारंभिक मूल्य है। यदि यह एक स्थानीय है (जैसा कि दिखाया गया है) यह लगभग निश्चित रूप से फू () के समान है। ("इस दशक में", उन्होंने तारीखों को देखते हुए जोड़ा)
greggo

16

मुझे पता है कि सवाल जीसीसी के बारे में है, लेकिन मुझे लगा कि अन्य कंपाइलरों के बारे में भी कुछ जानकारी रखना उपयोगी हो सकता है।

GCC की noinline फ़ंक्शन विशेषता अन्य संकलक के साथ-साथ बहुत लोकप्रिय है। यह कम से कम द्वारा समर्थित है:

  • क्लैंग (साथ जांचें __has_attribute(noinline))
  • इंटेल C / C ++ कंपाइलर (उनका दस्तावेज़ीकरण भयानक है, लेकिन मुझे यकीन है कि यह 16.0+ पर काम करता है)
  • ओरेकल सोलारिस स्टूडियो कम से कम 12.2 पर वापस
  • ARM C / C ++ कंपाइलर कम से कम 4.1 पर वापस
  • IBM XL C / C ++ कम से कम 10.1 पर वापस
  • TI 8.0+ (या 7.3+ --gcc के साथ, जो परिभाषित करेगा __TI_GNU_ATTRIBUTE_SUPPORT__)

इसके अतिरिक्त, MSVC __declspec(noinline) विजुअल स्टूडियो 7.1 में वापस सपोर्ट करता है । इंटेल शायद इसका समर्थन भी करता है (वे जीसीसी और एमएसवीसी दोनों के साथ संगत होने की कोशिश करते हैं), लेकिन मैंने इसे सत्यापित करने की जहमत नहीं उठाई। सिंटैक्स मूल रूप से समान है:

__declspec(noinline)
static void foo(void) { }

PGI 10.2+ (और शायद पुराने) एक प्रण का समर्थन करता है noinlineजो अगले फ़ंक्शन पर लागू होता है:

#pragma noinline
static void foo(void) { }

TI 6.0+ एक ऐसे FUNC_CANNOT_INLINE प्रज्ञा का समर्थन करता है जो (गुस्से में) C और C ++ में अलग तरह से काम करता है। C ++ में, यह PGI के समान है:

#pragma FUNC_CANNOT_INLINE;
static void foo(void) { }

C में, हालांकि, फ़ंक्शन नाम आवश्यक है:

#pragma FUNC_CANNOT_INLINE(foo);
static void foo(void) { }

Cray 6.4+ (और संभवतः पहले) एक समान दृष्टिकोण लेता है, जिसमें फ़ंक्शन नाम की आवश्यकता होती है:

#pragma _CRI inline_never foo
static void foo(void) { }

ओरेकल डेवलपर स्टूडियो भी एक प्रज्ञा का समर्थन करता है जो फ़ंक्शन का नाम लेता है , कम से कम Forte डेवलपर 6 पर वापस जा रहा है , लेकिन ध्यान दें कि इसे घोषणा के बाद आने की आवश्यकता है , यहां तक ​​कि हाल के संस्करणों में भी:

static void foo(void);
#pragma no_inline(foo)

आप कितने समर्पित हैं, इसके आधार पर, आप एक ऐसा मैक्रो बना सकते हैं जो हर जगह काम करेगा, लेकिन आपको फ़ंक्शन नाम के साथ-साथ तर्कों के रूप में घोषणा की आवश्यकता होगी।

यदि, OTOH, तो आप कुछ के साथ ठीक हैं जो कि ज्यादातर लोगों के लिए काम करता है, आप कुछ ऐसी चीज़ों से दूर हो सकते हैं जो थोड़ा अधिक सौंदर्यवादी रूप से मनभावन है और खुद को दोहराने की आवश्यकता नहीं है। यही कारण है कि दृष्टिकोण मैं के लिए ले जाया गया है हेडली , जहां के वर्तमान संस्करण HEDLEY_NEVER_INLINE की तरह दिखता है:

#if \
  HEDLEY_GNUC_HAS_ATTRIBUTE(noinline,4,0,0) || \
  HEDLEY_INTEL_VERSION_CHECK(16,0,0) || \
  HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
  HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
  HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
  HEDLEY_TI_VERSION_CHECK(8,0,0) || \
  (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__))
#  define HEDLEY_NEVER_INLINE __attribute__((__noinline__))
#elif HEDLEY_MSVC_VERSION_CHECK(13,10,0)
#  define HEDLEY_NEVER_INLINE __declspec(noinline)
#elif HEDLEY_PGI_VERSION_CHECK(10,2,0)
#  define HEDLEY_NEVER_INLINE _Pragma("noinline")
#elif HEDLEY_TI_VERSION_CHECK(6,0,0)
#  define HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;")
#else
#  define HEDLEY_NEVER_INLINE HEDLEY_INLINE
#endif

यदि आप Hedley (यह एक एकल सार्वजनिक डोमेन / CC0 हेडर है) का उपयोग नहीं करना चाहते हैं, तो आप बहुत अधिक प्रयास किए बिना संस्करण की जाँच करने वाले मैक्रोज़ को परिवर्तित कर सकते हैं, लेकिन इससे अधिक मैं ☺ में डालने के लिए तैयार हूं।


आपके प्रोजेक्ट @nemequ के लिंक के लिए धन्यवाद। मैंने अपने अन्य डेवलपर्स से हमारे उपयोग के लिए इसका मूल्यांकन करने के लिए कहा है। हमारे पास विविध आर्किटेक्चर हैं।
Daisuke Aramaki

मुझे यह जानने में बहुत रुचि होगी कि वे क्या कहते हैं, खासकर यदि वे रुचि नहीं रखते हैं। और, ज़ाहिर है, मैं सवालों के जवाब देने के लिए तैयार हूं (GitHub मुद्दा ट्रैकर, ई-मेल, जो कुछ भी ...)।
nemequ

14

यदि आपको इसके लिए संकलक त्रुटि मिलती है __attribute__((noinline)), तो आप बस कोशिश कर सकते हैं:

noinline int func(int arg)
{
    ....
}

10
static __attribute__ ((noinline))  void foo()
{

}

इसी से मेरा काम बना है।


8

noinline विशेषता का उपयोग करें :

int func(int arg) __attribute__((noinline))
{
}

जब आप बाहरी उपयोग के लिए फ़ंक्शन की घोषणा करते हैं और जब आप फ़ंक्शन लिखते हैं तो आपको संभवतः इसका उपयोग करना चाहिए।


2

मैं gcc 7.2 के साथ काम करता हूं। मुझे विशेष रूप से गैर-अंतर्निर्मित होने के लिए एक फ़ंक्शन की आवश्यकता थी, क्योंकि यह एक पुस्तकालय में तत्काल किया जाना था। मैंने __attribute__((noinline))जवाब देने की कोशिश की , साथ ही asm("")जवाब भी। न ही किसी ने समस्या का समाधान किया।

अंत में, मुझे लगा कि फ़ंक्शन के अंदर एक स्थैतिक चर को परिभाषित करने से संकलक को स्थिर चर खंड में इसके लिए जगह आवंटित करने के लिए मजबूर किया जाएगा, और जब फ़ंक्शन पहले कहा जाता है, तो इसके लिए एक इनिशियलाइज़ेशन जारी करने के लिए।

यह एक गंदी चाल की तरह है, लेकिन यह काम करता है।


आप अपने फ़ंक्शन inline void foo(void) { ... }को हेडर में परिभाषित कर सकते हैं और इसे extern inline void foo(void);लाइब्रेरी सोर्स फ़ाइल में घोषित कर सकते हैं । C99 शब्दार्थ के बाद, संकलक को फ़ंक्शन को इनलाइन करने की अनुमति दी जाएगी जब वह आपके पुस्तकालय में ऑब्जेक्ट कोड को प्रसन्न और उत्सर्जित करता है। "स्थिर" या "बाह्य" बिना "इनलाइन" देखें C99 में कभी उपयोगी?
डायपर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.