2012-05-01 9 views
40

यह प्रश्न बहुत विशिष्ट नहीं है; यह वास्तव में मेरे अपने संवर्धन के लिए है और मुझे उम्मीद है कि अन्य इसे भी उपयोगी पा सकते हैं।जीसीसी स्टेटमेंट एक्सप्रेशन का उपयोग कर बेनामी फ़ंक्शन

अस्वीकरण: मुझे पता है कि कई लोगों के पास जवाब देने का आवेग होगा "यदि आप एफपी करने की कोशिश कर रहे हैं तो बस एक कार्यात्मक भाषा का उपयोग करें"। मैं एक एम्बेडेड वातावरण में काम करता हूं जिसे कई अन्य सी पुस्तकालयों से जोड़ने की ज़रूरत होती है, और इसमें कई अधिक साझा साझा libs के लिए अधिक जगह नहीं है और कई भाषा रनटाइम का समर्थन नहीं करता है। इसके अलावा, गतिशील स्मृति आवंटन प्रश्न से बाहर है। मैं भी वास्तव में उत्सुक हूँ।

हम में से कई लैम्ब्डा भाव के लिए इस गंधा सी मैक्रो देखा है:

#define lambda(return_type, function_body) \ 
({ \ 
     return_type __fn__ function_body \ 
      __fn__; \ 
}) 

और एक उदाहरण के उपयोग है:

int (*max)(int, int) = ({ int __fn__ (int x, int y) { return x > y ? x : y; } __fn__; }); 
:

int (*max)(int, int) = lambda (int, (int x, int y) { return x > y ? x : y; }); 
max(4, 5); // Example 

gcc -std=c89 -E test.c का उपयोग करना, लैम्ब्डा के लिए विस्तारित

तो, ये मेरे प्रश्न हैं:

  1. लाइन int (* एक्स) क्या रेखा ठीक से करता है; घोषित करें? बेशक, int * एक्स; एक पूर्णांक के लिए एक सूचक है, लेकिन इन दोनों अलग कैसे हैं?

  2. एक्सपेन्डेड मैक्रो पर एक नज़र डालने पर, पृथ्वी पर क्या अंतिम __fn__ करता है? अगर मैं एक परीक्षण समारोह void test() { printf("hello"); } test; लिखता हूं - जो तुरंत एक त्रुटि फेंकता है। मैं उस वाक्यविन्यास को समझ नहीं पा रहा हूं।

  3. डीबगिंग के लिए इसका क्या अर्थ है? (मैं खुद और जीडीबी के साथ प्रयोग करने की योजना बना रहा हूं, लेकिन दूसरों के अनुभव या राय बहुत अच्छी होंगी)। क्या यह स्थिर विश्लेषकों को खराब कर देगा?

+3

यह एएनएसआई सी –

+0

इसके अलावा, मैं' पूर्णांक (* एक्स) नहीं दिख रहा है नहीं है। –

+0

यह इस तरह में नहीं है। वाक्यविन्यास को समझने की कोशिश करते समय, मैं थोड़ा सा स्टंप था कि int (* एक्स); संकलित करता है, लेकिन वास्तव में यह सुनिश्चित नहीं करता कि यह क्या परिभाषित किया गया है .. –

उत्तर

31

यह (ब्लॉक गुंजाइश पर) घोषणा:

int (*max)(int, int) = 
    ({ 
    int __fn__ (int x, int y) { return x > y ? x : y; } 
    __fn__; 
    }); 

सी नहीं है, लेकिन वैध जीएनयू सी है

यह बनाता है दो gcc एक्सटेंशन के उपयोग:

  1. nested functions
  2. statement expressions

दोनों नेस्टेड कार्यों (एक यौगिक बयान के अंदर एक समारोह को परिभाषित) और बयान भाव (({}) , मूल रूप से एक ब्लॉक जो मूल्य उत्पन्न करता है) को सी और कॉम में अनुमति नहीं है ई जीएनयू सी

एक बयान अभिव्यक्ति में से, पिछले अभिव्यक्ति बयान निर्माण का मूल्य है। यही कारण है कि नेस्टेड फ़ंक्शन __fn__ कथन अभिव्यक्ति के अंत में एक अभिव्यक्ति कथन के रूप में प्रकट होता है। एक अभिव्यक्ति में एक फ़ंक्शन डिज़ाइनर (__fn__) अभिव्यक्ति में सामान्य रूपांतरणों द्वारा किसी फ़ंक्शन में पॉइंटर में परिवर्तित हो जाता है। यह फ़ंक्शन पॉइंटर max प्रारंभ करने के लिए उपयोग किया जाने वाला मान है।

+3

ऐसी उपयोगी कार्यक्षमता, इसे एएनएसआई सी में कब लागू किया जाएगा? – Pacerier

+1

यह वाक्य रचनात्मक रूप से मान्य जीएनयू सी है, लेकिन क्या यह वास्तव में अर्थात् वैध है? जब फंक्शन परिभाषा वाले ब्लॉक से बाहर निकलता है (जो "लैम्ब्डा अभिव्यक्ति" के किसी भी वास्तविक उपयोग से पहले हो सकता है), तो फ़ंक्शन ट्रैम्पोलिन को इसके साथ अमान्य नहीं किया जाएगा? – Dolda2000

+0

@ Dolda2000 डेटा एक कथन अभिव्यक्ति में बनाया गया डेटा शायद स्थिर अवधि है। आखिरकार, यह अब एएनएसआई सी नहीं है। यह जीएनयू सी है जीएनयू उस मानक को परिभाषित करता है। –

0
  1. int (*max)(int, int) चर के प्रकार आप की घोषणा कर रहे हैं। इसे अधिकतम नामक फ़ंक्शन पॉइंटर के रूप में परिभाषित किया जाता है जो int देता है, और पैरामीटर के रूप में दो इन्स लेता है।

  2. __fn__ फ़ंक्शन नाम को संदर्भित करता है, जो इस मामले में अधिकतम है।

  3. मेरे पास कोई जवाब नहीं है। मुझे लगता है कि अगर आप प्रीप्रोसेसर के माध्यम से इसे चला चुके हैं तो आप इसके माध्यम से कदम उठा सकते हैं।

+0

wrt 2, मुझे समझ में नहीं आता कि क्यों int (* अधिकतम) (int, int) = ({int __fn__ (int x, int y) {return x> y? x : y;} __fn__;}); 'संकलित करें, लेकिन' शून्य परीक्षण() {puts ("हैलो"); } परीक्षण; * * नहीं * संकलन? –

+0

@ बीवीबी। मैं कोड को बिल्कुल समान दिखता हूं। 'शून्य (* परीक्षण)() = ({शून्य परीक्षण() {डालता है (" हैलो ");} परीक्षण;}); 'या यदि यह काम नहीं करता है,' शून्य (* परीक्षण)() = ({ शून्य __fn __() {डालता है ("हैलो");} __fn__;}); ' – gcochard

+0

' __fn__' ब्लॉक के अंदर परिभाषित फ़ंक्शन के लिए केवल एक मनमाना नाम है। नामकरण दुर्भाग्य से भ्रमित है। – FooF

0

आंशिक जवाब: यह int नहीं है (* एक्स) आप में रुचि रखते हैं यह पूर्णांक है (* एक्स) (y, z)।। यह एक्स नामक फ़ंक्शन के लिए एक फ़ंक्शन पॉइंटर है जो लेता है (y, z) और int देता है।

डीबगिंग के लिए, यह वास्तव में कठिन होगा। अधिकांश डिबगर्स एक मैक्रो के माध्यम से पता नहीं लगा सकते हैं। आपको असेंबली को डीबग करना होगा।

5

आपका लैम्ब्डा मैक्रो दो फंकी सुविधाओं का शोषण करता है। पहले यह नीडिंत कार्यों का उपयोग करता वास्तव में परिभाषित करने के लिए अपने समारोह के शरीर (ताकि आपके लैम्ब्डा वास्तव में अनाम नहीं है, यह सिर्फ, एक अंतर्निहित __fn__ चर (जो कुछ और करने के लिए नाम दिया जाना चाहिए का उपयोग करता है डबल अग्रणी अंडरस्कोर नाम के लिए आरक्षित हैं के रूप में संकलक, इसलिए हो सकता है yourapp__fn__ की तरह कुछ बेहतर होगा)

यह अपने आप में एक जीसीसी यौगिक कथन में किया जाता है सब के सब (http://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html#Statement-Exprs देखें), बुनियादी प्रारूप जिनमें से कुछ इस तरह चला जाता है:।

({ ...; retval; }) 

यौगिक बयान का अंतिम बयान सिर्फ घोषित समारोह का पता है। अब, int (*max)(int,int) को यौगिक कथन का मान सौंपा गया है, जो अभी घोषित 'अज्ञात' फ़ंक्शन का सूचक है।

डिबगिंग मैक्रो निश्चित रूप से एक शाही दर्द कर रहे हैं।

कारण के कारण test; .. कम से कम यहां, मुझे 'परीक्षण को विभिन्न प्रकार के प्रतीक के रूप में पुनः प्राप्त किया गया' मिलता है, जिसका मुझे लगता है कि जीसीसी इसे घोषणा के रूप में मान रहा है, न कि (बेकार) अभिव्यक्ति। क्योंकि untyped चर डिफ़ॉल्ट int के लिए और क्योंकि आप पहले से test एक समारोह के रूप में घोषित किया है (अनिवार्य रूप से, void (*)(void)) आपको लगता है कि .. मिलता है लेकिन मुझे लगता है कि के बारे में गलत हो सकता है।

यह हालांकि कल्पना के किसी भी खिंचाव से पोर्टेबल नहीं है। `कहीं भी,

+0

+1 '__fn__' का नाम बदलने का सुझाव देने के लिए। – FooF

संबंधित मुद्दे