2010-10-27 8 views
20

सी ++ में कभी-कभी एक चर परिभाषित किया जाएगा, लेकिन उपयोग नहीं किया जाएगा। यहाँ एक उदाहरण है - COM_INTERFACE_ENTRY_FUNC_BLIND ATL मैक्रो साथ प्रयोग के लिए एक समारोह:एक "variableName;" सी ++ स्टेटमेंट हर समय नो-ऑप होता है?

HRESULT WINAPI blindQuery(void* /*currentObject*/, REFIID iid, void** ppv, DWORD_PTR /*param*/) 
{ 
    DEBUG_LOG(__FUNCTION__); //DEBUG_LOG macro expands to an empty string in non-debug 
    DEBUG_LOG(iid); 
    iid; // <<<<<<<----silence compiler warning 
    if(ppv == 0) { 
     return E_POINTER; 
    } 
    *ppv = 0; 
    return E_NOINTERFACE; 
} 

ऊपर के उदाहरण iid पैरामीटर DEBUG_LOG मैक्रो कि गैर डिबग विन्यास में कोई रिक्त स्ट्रिंग में विस्तारित साथ प्रयोग किया जाता है। इसलिए हस्ताक्षर में iid परिवर्तनीय नाम को टिप्पणी या निकालना एक विकल्प नहीं है। जब गैर-डीबग कॉन्फ़िगरेशन संकलित किए जा रहे हैं तो संकलक C4100: 'iid' : unreferenced formal parameter चेतावनी को स्पैन करता है, इसलिए चेतावनी को शांत करने के लिए iid; कथन जिसे नो-ऑप माना जाता है।

सवाल यह है: हर समय स्वतंत्र पर

variableName; 

हो नो-सेशन:

CSomeType variableName; //or 
CSomeType& variableName; //or 
CSomeType* variableName; 

निम्नलिखित बयान सी ++ कोड में होगा: हम निम्नलिखित घोषणाओं से कोई भी अगर CSomeType क्या है?

+2

क्या यह "कथन का कोई प्रभाव नहीं पड़ता" चेतावनी नहीं देगा? – falstro

+0

@roe: यह विजुअल सी ++ पर नहीं है। शायद यह कुछ अन्य कंपाइलर्स पर करता है। – sharptooth

+0

अगर घोषणा और कथन के बीच आप प्रीप्रोसेसर का दुरुपयोग करते हैं तो इसका असर हो सकता है। उदाहरण के लिए '#define variableName निकास (-1) ' – Benoit

उत्तर

47

हां, लेकिन आपको शायद एक और चेतावनी मिल जाएगी।

ऐसा करने का मानक तरीका यह है: (void)iid;


बहुत तकनीकी रूप से, यह अभी भी एक रजिस्टर में iid लोड और कुछ भी नहीं कर सकता है। यह माना जाता है कि यह कंपाइलर्स भाग पर बेहद बेवकूफ है (मुझे संदेह है कि कोई भी ऐसा करेगा, अगर यह कंपाइलर को हटा देता है), लेकिन अगर अभिव्यक्ति को अनदेखा किया जाए तो यह एक और गंभीर मुद्दा है, आईओ कार्यों को कॉल करने जैसे अवलोकन योग्य व्यवहार से संबंधित कुछ है या volatile चर के पढ़ने और लिखना।

यह एक दिलचस्प सवाल लाता है: क्या हम एक अभिव्यक्ति ले सकते हैं और पूरी तरह से इसे अनदेखा कर सकते हैं?

है यही कारण है, कि हम क्या अब यह है:

#define USE(x) (void)(x) 

// use iid in an expression to get rid of warning, but have no observable effect 
USE(iid); 

// hm, result of expression is gone but expression is still evaluated 
USE(std::cout << "hmmm" << std::endl); 

यह एक समाधान के करीब है:

// sizeof doesn't evaluate the expression 
#define USE(x) (void)(sizeof(x)) 

लेकिन साथ विफल:

void foo(); 

// oops, cannot take sizeof void 
USE(foo()); 

समाधान बस है:

// use expression as sub-expression, 
// then make type of full expression int, discard result 
#define USE(x) (void)(sizeof((x), 0)) 

जो कोई ऑपरेशन की गारंटी देता है।

संपादित करें: ऊपर वास्तव में कोई प्रभाव नहीं की गारंटी है, लेकिन मैं परीक्षण के बिना पोस्ट। परीक्षण पर, यह कम से कम एमएसवीसी 2010 में एक चेतावनी उत्पन्न करता है, क्योंकि मान का उपयोग नहीं किया जाता है। यह कोई अच्छा नहीं है, अधिक चाल के लिए समय!


अनुस्मारक: हम इसका मूल्यांकन किए बिना अभिव्यक्ति का "उपयोग" करना चाहते हैं।यह कैसे किया जा सकता है? इस तरह:

#define USE(x) ((void)(true ? 0 : (x))) 

यह आखिरी बार (वास्तव में बदतर) की तरह एक साधारण समस्या है, कि (x) जरूरतों में int के लिए परिवर्तनीय हो सकता है। यह फिर से ठीक करने के लिए है, तुच्छ:

#define USE(x) ((void)(true ? 0 : ((x), 0))) 

और हम हम पिछली बार (कोई नहीं) था प्रभाव का एक ही तरह के वापस आ गए हैं, लेकिन इस बार x "पुराना" है तो हम कोई चेतावनी नहीं मिलता । सही किया?

वास्तव में इस समाधान के साथ अभी भी एक समस्या (पिछले अन-समाधान में उपहार के रूप में अच्छी तरह से और था, लेकिन ध्यान नहीं दिया गया) है, और यह इस उदाहरण में ऊपर आता है:

struct foo {}; 
void operator,(const foo&, int) {} 

foo f; 
USE(f); // oops, void isn't convertible to int! 

यही है, अगर (x) अभिव्यक्ति का प्रकार अल्पविराम ऑपरेटर को int में कनवर्ट करने योग्य नहीं है, समाधान विफल हो जाता है। बेशक, संभावना नहीं है, लेकिन पूरी तरह से पानी में गिर जाने के लिए, हम इसके साथ ठीक कर सकते हैं:

#define USE(x) ((void)(true ? 0 : ((x), void(), 0))) 

यकीन है कि हम वास्तव में शून्य के साथ खत्म करने के लिए। This trick brought to you by Johannes


के रूप में भी बताया गया है, यदि ऊपर पर्याप्त नहीं था, एक मूर्ख पर्याप्त संकलक संभावित "लोड" अभिव्यक्ति 0 (एक रजिस्टर या कुछ में), तो यह उपेक्षा कर सकता है।

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

+0

हालांकि मैं सहमत हूं, इसका मतलब यह नहीं है कि अभिव्यक्ति को नो-ऑप बनना है। कंपाइलर, अगर यह वांछित हो सकता है, तो एक रजिस्टर में मूल्य लोड करें और फिर इसे अनदेखा करें। हालांकि यह मूर्खतापूर्ण होगा यह अविश्वसनीय नहीं है कि एक अनुकूलन कंपाइलर कभी-कभी बिट्स छोड़ देता है। –

+0

@eda: इसे कुछ भी करने की आवश्यकता नहीं है। कृपया उद्धरण देखें [यहां] (http://stackoverflow.com/questions/4031228/why-is-operator-void-not-invoked-with-cast-syntax/4031487#4031487)। – GManNickG

+0

नहीं, अभिव्यक्ति "मान" को त्याग दिया गया है। किसी रजिस्टर में मान लोड हो रहा है, या अन्यथा CPU के अस्तित्व को इंगित करने से उस नियम का उल्लंघन नहीं होगा। जहां तक ​​भाषा का सवाल है, इसका कोई दुष्प्रभाव नहीं था। –

2

ठीक है, संकलक के स्रोत कोड को देखे बिना 100% निश्चितता के साथ कहना वास्तव में संभव नहीं है, लेकिन अगर मैं कभी आधुनिक कंपाइलरों में कोई कोड उत्पन्न करता हूं तो मुझे आश्चर्य होगा।

दिन के अंत में, यदि आप किसी विशेष घटना के बारे में चिंतित हैं तो आप हमेशा जेनरेट किए गए असेंबली कोड को देखने के लिए स्वतंत्र रहते हैं।

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