बाहरी इनलाइन क्या करती है?


93

मैं समझता हूँ कि inline संकलक के लिए एक सुझाव है, और अपने विवेक पर यह फ़ंक्शन को इनलाइन नहीं कर सकता है, और यह लिंक करने योग्य ऑब्जेक्ट कोड भी उत्पन्न करेगा।

मुझे लगता है कि static inline ऐसा ही (इनलाइन हो सकता है या नहीं भी) हो सकता है, लेकिन इनबिल्ट होने पर लिंक करने योग्य ऑब्जेक्ट कोड का उत्पादन नहीं करेगा (क्योंकि कोई अन्य मॉड्यूल इसे लिंक नहीं कर सकता)।

कहा पर extern inlineतस्वीर में फिट बैठता है?

मान लें कि मैं इनलाइन फ़ंक्शन द्वारा प्रीप्रोसेसर मैक्रो को प्रतिस्थापित करना चाहता हूं और आवश्यकता है कि यह फ़ंक्शन इनबिल्ड हो जाता है (जैसे, क्योंकि यह __FILE__और __LINE__मैक्रोज़ का उपयोग करता है जिसे कॉलर के लिए हल करना चाहिए लेकिन इसे फ़ंक्शन नहीं कहा जाता है)। यदि मैं फ़ंक्शन को इनलाइन नहीं करता है, तो मैं कंपाइलर या लिंकर त्रुटि देखना चाहता हूं। कर देता हैextern inline है? (मुझे लगता है कि, अगर ऐसा नहीं होता है, तो मैक्रो के साथ चिपके रहने के अलावा इस व्यवहार को प्राप्त करने का कोई तरीका नहीं है।)

क्या C ++ और C के बीच अंतर हैं?

क्या विभिन्न संकलक विक्रेताओं और संस्करणों के बीच अंतर हैं?

जवाबों:


129

K & R C या C89 में, इनलाइन भाषा का हिस्सा नहीं था। कई कंपाइलरों ने इसे एक विस्तार के रूप में लागू किया, लेकिन इस बारे में कोई परिभाषित शब्दार्थ नहीं था कि यह कैसे काम करता है। जीसीसी पहले इनलाइन करने को लागू करने के बीच में था, और शुरू की inline, static inlineऔर extern inlineनिर्माणों; अधिकांश पूर्व C99 कंपाइलर आमतौर पर इसके लीड का अनुसरण करते हैं।

GNU89:

  • inline: फ़ंक्शन को इनलाइन किया जा सकता है (हालांकि यह केवल एक संकेत है)। एक आउट-ऑफ-लाइन संस्करण हमेशा उत्सर्जित होता है और बाहरी रूप से दिखाई देता है। इसलिए आप केवल एक संकलन इकाई में इस तरह के इनलाइन को परिभाषित कर सकते हैं, और हर दूसरे को इसे एक आउट-ऑफ-लाइन फ़ंक्शन के रूप में देखने की जरूरत है (या आपको लिंक समय पर डुप्लिकेट प्रतीक मिलेंगे)।
  • extern inline एक आउट-ऑफ-लाइन संस्करण उत्पन्न नहीं करेगा, लेकिन एक को कॉल कर सकता है (जिसे आपको इसलिए किसी अन्य संकलन इकाई में परिभाषित करना होगा। एक-परिभाषा नियम लागू होता है, हालांकि, आउट-ऑफ-लाइन संस्करण में समान कोड होना चाहिए; इनलाइन की पेशकश की जाने की स्थिति में कंपाइलर कॉल के बजाय।
  • static inlineबाह्य रूप से दृश्यमान आउट-ऑफ-लाइन संस्करण उत्पन्न नहीं करेगा, हालांकि यह एक स्थिर फ़ाइल उत्पन्न कर सकता है। एक-परिभाषा नियम लागू नहीं होता है, क्योंकि कभी भी एक उत्सर्जित बाहरी प्रतीक नहीं होता है और न ही किसी को कॉल किया जाता है।

C99 (या GNU99):

  • inline: GNU89 की तरह "एक्सटर्नल इनलाइन"; कोई बाह्य रूप से दिखाई देने वाला फ़ंक्शन उत्सर्जित नहीं होता है, लेकिन किसी को बुलाया जा सकता है और इसलिए उसका अस्तित्व होना चाहिए
  • extern inline: जैसे GNU89 "इनलाइन": बाहरी रूप से दृश्यमान कोड उत्सर्जित होता है, इसलिए अधिकांश एक अनुवाद इकाई इसका उपयोग कर सकती है।
  • static inline: जैसे GNU89 "स्टैटिक इनलाइन"। यह केवल एक पोर्टेबल है जो gnu89 और c99 के बीच है

सी ++:

एक फ़ंक्शन जो कहीं भी इनलाइन है, हर जगह एक ही परिभाषा के साथ इनलाइन होना चाहिए। संकलक / लिंकर प्रतीक के कई उदाहरणों को हल करेगा। वहाँ की कोई परिभाषा है static inlineया extern inlineहालांकि कई compilers उन्हें (आमतौर पर gnu89 मॉडल का अनुसरण),।


2
क्लासिक क्लासिक सी में, 'इनलाइन' एक कीवर्ड नहीं था; यह एक चर नाम के रूप में उपयोग के लिए उपलब्ध था। यह C89 और पूर्व-मानक (K & R) C. पर लागू होगा
जोनाथन लेफ़लर

आप सही हैं, ऐसा लगता है। फिक्स्ड। मुझे लगा कि इसे C89 (हालांकि K & R में नहीं) में एक कीवर्ड के रूप में आरक्षित किया गया था, लेकिन मुझे लगता है कि मुझे गलत समझा गया है
puetzk

मैं Microsoft के विजुअल C ++ के लिए इसे जोड़ना चाहता हूं, इसमें एक __forceinline कीवर्ड है जो आपके फ़ंक्शन को इनलाइड करने को लागू करेगा। यह स्पष्ट रूप से केवल VC ++ के लिए एक संकलक-विशिष्ट विस्तार है।
अप्रकाशित unt४27

क्या C99 "एक्सटर्नल इनलाइन" और कोई स्पेसर के बीच कोई अंतर नहीं है?
जो सो

शब्दार्थ नहीं; एक गैर-इनलाइन फ़ंक्शन की तरह, extern inlineएक परिभाषा नियम के अधीन है, और यह परिभाषा है। लेकिन अगर कार्यान्वयन-परिभाषित अनुकूलन अनुकूलन inlineआंकड़े सुझाव के रूप में कीवर्ड का उपयोग करने के लिए अनुशंसा का पालन करते हैं कि "फ़ंक्शन को कॉल जितनी जल्दी हो सके" (आईएसओ 9899: 1999 .76.7.4 (5), extern inlineमायने रखता है
पुएट्ज़

31

मेरा मानना ​​है कि आप इस कथन के आधार पर __FILE__ और __LINE__ को गलत समझ रहे हैं:

क्योंकि यह __FILE__ और __LINE__ मैक्रोज़ का उपयोग करता है जिसे कॉल करने वाले के लिए हल करना चाहिए लेकिन इसे फ़ंक्शन नहीं कहा जाता है

संकलन के कई चरण हैं, और प्रीप्रोसेसिंग पहला है। उस चरण के दौरान __FILE__ और __LINE__ को बदल दिया जाता है। इसलिए जब तक कंपाइलर इनलाइनिंग के फंक्शन पर विचार कर सकता है, तब तक वे बदल चुके होते हैं।


14

ऐसा लगता है कि आप कुछ इस तरह लिखने की कोशिश कर रहे हैं:

inline void printLocation()
{
  cout <<"You're at " __FILE__ ", line number" __LINE__;
}

{
...
  printLocation();
...
  printLocation();
...
  printLocation();

और उम्मीद है कि आपको हर बार अलग-अलग मूल्य मुद्रित होंगे। जैसा कि डॉन कहते हैं, आप नहीं करेंगे, क्योंकि __FILE__ और __LINE__ प्रीप्रोसेसर द्वारा कार्यान्वित किए जाते हैं, लेकिन इनलाइन कंपाइलर द्वारा कार्यान्वित किया जाता है। इसलिए जहां से भी आप प्रिंटलोकेशन कहते हैं, आपको वही परिणाम मिलेगा।

आपको काम करने का एकमात्र तरीका प्रिंटलोकेशन को मैक्रो बनाना है। (हाँ मैं जानता हूँ...)

#define PRINT_LOCATION  {cout <<"You're at " __FILE__ ", line number" __LINE__}

...
  PRINT_LOCATION;
...
  PRINT_LOCATION;
...

18
फंक्शन और लाईन को पैरामीटर्स के रूप में पास करने के लिए एक फंक्शन प्रिंटलोकेशन कॉल करने के लिए मैक्रो PRINT_LOCATION के लिए एक सामान्य ट्रिक है । इसका परिणाम बेहतर डिबगर / संपादक / आदि व्यवहार में हो सकता है जब फ़ंक्शन बॉडी गैर-तुच्छ हो।
स्टीव जेसप

@ रोडी मेरे समाधान को देखो - तुम्हारा विस्तार लेकिन अधिक व्यापक और एक्स्टेंसिबल।
उत्साही

@SteveJessop जैसा कुछ मैंने नीचे समाधान में सूचीबद्ध किया है?
उत्साही

3

इनलाइन, स्टेटिक इनलाइन और एक्सटर्न इनलाइन के साथ स्थिति जटिल है, कम से कम नहीं है क्योंकि gcc और C99 उनके व्यवहार के लिए थोड़े अलग अर्थों को परिभाषित करते हैं (और संभवतः C ++, साथ ही साथ)। आप सी में वे यहां क्या करते हैं, इसके बारे में कुछ उपयोगी और विस्तृत जानकारी पा सकते हैं ।


2

इनरोल फ़ंक्शंस के बजाय मैक्रोज़ आपकी पसंद हैं। एक दुर्लभ अवसर जहां मैक्रोज़ इनलाइन कार्यों पर शासन करते हैं। निम्नलिखित को आज़माएं: मैंने यह "मैक्रो मैजिक" कोड लिखा है और यह काम करना चाहिए! 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 फ़ाइलों में समान है। जहां भी संभव हो मैक्रोज़ पर इनलाइन फ़ंक्शंस या कास्ट आइडेंटिफ़ायर (केस की मांग के अनुसार) को प्राथमिकता दें।


2

उत्तर देने के बजाय "यह क्या करता है?", मैं जवाब दे रहा हूं "मैं इसे कैसे बना सकता हूं जो मुझे चाहिए?" जीएनयू C89, मानक C99 और C ++: सभी में 5 प्रकार की इनलाइनिंग उपलब्ध हैं।

हमेशा इनलाइन, जब तक पता न चले

__attribute__((always_inline))किसी भी घोषणा में जोड़ें , फिर उसके पते की संभावना को संभालने के लिए नीचे दिए गए मामलों में से एक का उपयोग करें।

आपको इसका उपयोग कभी नहीं करना चाहिए, जब तक कि आपको इसके शब्दार्थ की आवश्यकता न हो (जैसे कि एक निश्चित तरीके से विधानसभा को प्रभावित करने के लिए, या उपयोग करने के लिए alloca)। कंपाइलर आमतौर पर आपसे बेहतर जानता है कि क्या इसके लायक है।

इनलाइन और एक कमजोर प्रतीक का उत्सर्जन करें (जैसे C ++, उर्फ ​​"बस इसे काम करें")

__attribute__((weak))
void foo(void);
inline void foo(void) { ... }

ध्यान दें कि यह समान कोड की प्रतियों का एक गुच्छा छोड़ देता है, और लिंकर एक मनमाने ढंग से चुनता है।

इनलाइन, लेकिन कभी भी किसी प्रतीक का उत्सर्जन न करें (बाहरी संदर्भ छोड़कर)

__attribute__((gnu_inline))
extern inline void foo(void) { ... }

हमेशा (एक टीयू के लिए, पूर्ववर्ती समाधान के लिए) का उत्सर्जन करें

संकेतित संस्करण C ++ में एक कमजोर प्रतीक है, लेकिन C की किसी भी बोली में एक मजबूत प्रतीक है:

void foo(void);
inline void foo(void) { ... }

या आप इसे संकेत के बिना कर सकते हैं, जो दोनों भाषाओं में एक मजबूत प्रतीक का उत्सर्जन करता है:

void foo(void) { ... }

आम तौर पर, आप जानते हैं कि जब आप परिभाषाएँ प्रदान कर रहे हैं, तब आपकी टीयू किस भाषा में है, और शायद बहुत अधिक ज़रूरत नहीं है।

हर टीयू में इनलाइन और एमिट

static inline void foo(void) { ... }

staticएक को छोड़कर इन सभी के लिए , आप void foo(void)ऊपर एक घोषणा जोड़ सकते हैं । यह साफ हेडर लिखने के "सर्वोत्तम अभ्यास" के साथ मदद करता है, फिर #includeइनलाइन परिभाषाओं के साथ एक अलग फाइल को इनगेट करता है। फिर, यदि सी-स्टाइल इनलाइन्स का उपयोग किया जाता है,#define कुछ मैक्रो अलग-अलग एक में समर्पित टीयू को आउट-ऑफ-लाइन परिभाषा प्रदान करते हैं।

extern "C"अगर हेडर का उपयोग C और C ++ दोनों से किया जा सकता है, तो यह न भूलें


गुम: MSVC के बारे में क्या? इसमें कुछ C89 बोली एक्सटेंशन हैं, लेकिन मैं कभी भी MSVC का उपयोग नहीं करता और यह नहीं जानता कि इसके nmसमकक्ष कैसे चलाया जाए ।
o11c
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.