2013-10-10 7 views
6

अक्सर, फ़ंक्शन घोषणा प्रदान करने के अतिरिक्त, सी मानक शीर्षलेख चीजों को तेज बनाने के लिए "मास्किंग मैक्रो" प्रदान कर सकते हैं। उदाहरण के लिए, अगर मैं ctype.h में शामिल हैं, हेडर फाइल घोषणा करेंगेक्या सी मानक के लिए कोई प्रतिबंध है जो मैक्रोज़ के रूप में कार्यान्वित किए जाने की अनुमति देता है?

int isdigit(int c); 

लेकिन यह भी एक मैक्रो के साथ घोषणा मुखौटा हो सकता है। मेरा मानना ​​है कि सी मानक के अनुसार इस एक पोर्टेबल isdigit मैक्रो है:

#define isdigit(c) ((c) >= '0' && (c) <= '9') 
बेशक

, इस मैक्रो क्योंकि यह अपरिभाषित व्यवहार का परिचय भी खतरनाक है अगर आप ऐसा करते हैं, जबकि मैक्रो परिभाषित किया गया है:

int c = 'A'; 
printf("%d\n", isdigit(c++)); 

इस कल्पित मामले में यूबी से बचने के लिए, मुझे फ़ंक्शन नाम को अभिभावकों के साथ घूमना होगा: (isdigit)(c++)। तो, मेरा सवाल यह है: क्या कोई मानक हैडरिंग मैक्रोज़ मैक्रोज़ मैक्रोज़ को परिभाषित करने के लिए कोई प्रतिबंध है? क्या वे अपरिभाषित व्यवहार का कारण नहीं बनने की गारंटी देते हैं यदि तर्क अभिव्यक्ति के दुष्प्रभाव होते हैं, या क्या वे तकनीकी रूप से अजीब व्यवहार करने की अनुमति देते हैं जैसे कि हम ऊपर देखते हैं? सीमाएं कहां हैं?

+0

आपने प्रस्तावित मैक्रो अनुरूप नहीं है। 'Getc()' और 'putc() 'फ़ंक्शंस के (वैकल्पिक) मैक्रो कार्यान्वयन के अपवादों के साथ, मानक फ़ंक्शन की एक मैक्रो परिभाषा एक से अधिक बार अपने किसी भी तर्क का मूल्यांकन नहीं कर सकती है। यदि आपके मैक्रो misbehaves 'isdigit (C++) 'के रूप में लागू किया गया है, लेकिन कथन अनुपालन मैक्रोज़ और फ़ंक्शन के साथ सही तरीके से काम करता है। –

+0

क्षमा करें, "मानक मैक्रोज़" से आपका क्या मतलब है? किसी भी मामले में, जब मैंने "पोर्टेबल" कहा, तो मेरा मतलब "सभी मानक-अनुपालन सी कंपाइलरों पर अच्छी तरह से व्यवहार किया गया", जब साइड इफेक्ट्स के बिना उचित तर्क पारित किया गया। –

+0

सी मानक बताता है कि किसी भी मानक समारोह को मैक्रो के रूप में भी लागू किया जा सकता है। लेकिन यह भी मांग करता है कि किसी भी मानक सी फ़ंक्शन के किसी भी मैक्रो कार्यान्वयन ('getc()' और 'putc()' को छोड़कर) केवल एक बार अपने तर्कों का मूल्यांकन करना चाहिए, क्योंकि मैक्रो को बिल्कुल कार्य करना चाहिए जैसे कि यह एक कार्य था। इसके अलावा, प्रत्येक कार्य को एक समारोह के रूप में घोषित और कार्यान्वित किया जाना चाहिए ताकि उसका पता लिया जा सके और काम करने के लिए सूचक के रूप में चारों ओर पारित किया जा सके। पॉल ग्रिफिथ्स ने आपको मानक से उद्धृत किया है कि यह जानकारी बहुत अधिक है। ध्यान दें कि 'setjmp() 'स्पष्ट रूप से एक मैक्रो है। –

उत्तर

5
प्रति C11 7.1.4.1

,, विशेष रूप से अंतिम भाग नीचे उद्धृत "पुस्तकालय कार्य का प्रयोग":

किसी भी समारोह एक शीर्षक में घोषित अतिरिक्त में परिभाषित एक समारोह की तरह मैक्रो के रूप में लागू किया जा सकता हेडर, इसलिए अगर लाइब्रेरी फ़ंक्शन स्पष्ट रूप से घोषित किया गया है कि उसके शीर्षलेख को शामिल किया गया है, तो नीचे दिखाए गए तकनीकों में से एक का उपयोग यह सुनिश्चित करने के लिए किया जा सकता है कि घोषणा ऐसी मैक्रो से प्रभावित नहीं है .... उसी वाक्य रचनात्मक कारण के लिए, को लाइब्रेरी फ़ंक्शन का पता लेने की अनुमति है भले ही यह भी मा के रूप में परिभाषित किया गया हो सीआरओ। किसी भी मैक्रो परिभाषा को हटाने के लिए #undef का उपयोग यह भी सुनिश्चित करेगा कि वास्तविक कार्य को संदर्भित किया जाए। किसी भी एक मैक्रो के रूप में लागू किए गए लाइब्रेरी फ़ंक्शन का आविष्कार कोड में विस्तारित होगा जो कि प्रत्येक बार अपने तर्कों का मूल्यांकन करता है, जहां आवश्यक हो वहां पूरी तरह से ब्रांड्स द्वारा संरक्षित है, इसलिए आमतौर पर तर्क के रूप में मनमाने ढंग से अभिव्यक्तियों का उपयोग करने के लिए सुरक्षित है।

ध्यान दें कि अंत में "आम तौर पर" महत्वपूर्ण है, और स्पष्ट अपवाद हैं। सी 11 7.21.7.5.2 कहता है "getc फ़ंक्शन fgetc के बराबर है, सिवाय इसके कि यदि इसे मैक्रो के रूप में कार्यान्वित किया गया है, तो यह stream का मूल्यांकन एक से अधिक बार कर सकता है, इसलिए तर्क कभी साइड इफेक्ट्स के साथ अभिव्यक्ति नहीं होना चाहिए", इसी भाषा के साथ C11 7.21.7.7.2 में putc के लिए। इस विशेष मामले में, stream एक FILE * है, इसलिए सामान्य परिस्थितियों में यह दुष्प्रभावों के साथ अभिव्यक्ति के रूप में अजीब होगा, लेकिन ऐसा हो सकता है। उनके विस्तृत चरित्र समकक्षों के लिए भी यह सच है, putwc() और getwc()। मुझे इस तरह के किसी अन्य अपवाद की जानकारी नहीं है।

+0

दिलचस्प - मुझे आश्चर्य है कि getc() और putc() आवश्यकताओं को वास्तव में C11 (या उस मामले के लिए C99) में बदल दिया गया था ... मेरा जवाब देखें। –

+0

मुझे लगता है कि अंतिम वाक्य में "आम तौर पर" महत्वपूर्ण है। प्रति सी 11 7.21.7.5.2, "' getc' फ़ंक्शन 'fgetc' के बराबर है, सिवाय इसके कि यदि इसे मैक्रो के रूप में कार्यान्वित किया गया है, तो यह एक से अधिक बार' स्ट्रीम' का मूल्यांकन कर सकता है, इसलिए तर्क कभी अभिव्यक्ति नहीं होना चाहिए साइड इफेक्ट्स ", इसलिए मुझे लगता है कि आप अभी भी सही हैं। –

+2

'getc()' और 'putc()' अपवाद सी 8 9 (और सी 99) के साथ-साथ सी 11 में मौजूद थे। उद्देश्य एक मैक्रो कार्यान्वयन की अनुमति देना है जो सामान्य रूप से किसी भी फ़ंक्शन कॉल से बचाता है, लेकिन ऐसे मैक्रोज़ को फ़ाइल स्ट्रीम तर्क का मूल्यांकन कई बार करना मुश्किल लगता है। जीसीसी इसे अभिव्यक्ति बयान प्रदान करता है क्योंकि इसे सब कुछ है; हालांकि, वे एक जीसीसी एक्सटेंशन हैं, मानक सी कंपाइलर सुविधा नहीं। –

1

यहाँ से: http://www.qnx.com/developers/docs/6.5.0/index.jsp?topic=%2Fcom.qnx.doc.dinkum_en_ecpp%2Flib_over.html

तर्क है कि दुष्प्रभाव उसी तरह अभिव्यक्ति मैक्रो विस्तार कार्यान्वित या फ़ंक्शन को कॉल करने के लिए कि क्या मूल्यांकन करते हैं। कार्यों के लिए मैक्रोज़ getc और putc इस नियम के लिए स्पष्ट अपवाद हैं।

मुझे कुछ अन्य संदर्भ एक ही चीज़ के बारे में कह रहे हैं (हालांकि सीधे सी मानक का हवाला देते हुए कुछ भी नहीं)।

तो ऐसा लगता है कि सीमाएं केवल getc() और putc() आपके द्वारा देखे जाने वाले तरीके से विनाश का कारण बन सकती हैं। उन दोनों के अलावा, आपको सुरक्षित होना चाहिए, मान लीजिए कि आपका मंच कम से कम एक सौहार्दपूर्ण या अनुरूप है।

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

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