[英]Will a “variableName;” C++ statement be a no-op at all times?
在C ++中,有時會定義一個變量,但不會使用。 這是一個示例-與COM_INTERFACE_ENTRY_FUNC_BLIND
ATL宏一起使用的函數:
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
宏一起使用, DEBUG_LOG
宏在非調試配置中擴展為空字符串。 因此,注釋掉或刪除簽名中的iid
變量名稱不是一種選擇。 編譯非調試配置時,編譯器會生成C4100: 'iid' : unreferenced formal parameter
警告,因此,為了使警告iid;
保持靜默iid;
添加被認為是無操作的語句。
問題如下:如果我們有以下任何聲明:
CSomeType variableName; //or
CSomeType& variableName; //or
CSomeType* variableName;
將在C ++代碼中執行以下語句:
variableName;
始終保持無操作狀態,而與CSomeType
是什么CSomeType
?
是的,但是您可能還會收到另一個警告。
這樣做的標准方法是: (void)iid;
。
從技術上講,這仍然可以將iid
加載到寄存器中,並且什么也不做。 當然,在編譯器方面這是非常愚蠢的(如果它確實刪除了編譯器,我懷疑有人會這樣做),但是如果要忽略的表達式涉及可觀察到的行為(例如,對IO函數的調用或閱讀和寫作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))
這保證了沒有操作。
編輯:以上確實保證沒有效果,但是我沒有測試就發布了。 經過測試,它至少在MSVC 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)))
為確保我們最終得到零。 約翰內斯帶給你的這個把戲 。
還要注意的是,如果以上操作還不夠,那么足夠愚蠢的編譯器可能會將表達式0
(裝入寄存器或其他東西)“加載”,然后忽略它。
我認為這是不可能擺脫的,因為我們最終需要一個表達式來導致某種類型的類型被忽略,但是如果我想到了,我會添加它。
好吧,如果不查看編譯器的源代碼,實際上不可能100%地確定,但是如果在現代編譯器中生成任何代碼,我將感到非常驚訝。
歸根結底,如果您擔心任何特定的實例,那么您隨時可以查看生成的匯編代碼。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.