簡體   English   中英

是'警告C4127`(條件表達式是不變的)有用嗎?

[英]is `warning C4127` (conditional expression is constant) ever helpful?

回答這篇文章時,我建議對多行宏使用do {...} while(0)

在MSVC上,我發現此代碼拋出:

warning C4127: conditional expression is constant

為了使代碼無警告,我需要選擇以下丑陋的替代方案之一:

選項1

#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4127)
#endif
code_using_macro_that_generates_C4217;
#ifdef _MSC_VER
#pragma warning(pop)
#endif

選項2
將我的宏定義為:

#define MULTI_LINE_MACRO do { ... } while(0,0)

要么

#define MULTI_LINE_MACRO do { ... } while((void)0,0)

一些程序員也稱為“貓頭鷹”,因為(0,0)看起來像貓頭鷹。

選項3
定義一個新的宏WHILE_0,它不會生成警告並使用它而不是while(0)

問題
我相信所有選擇都或多或少都是可怕的。 為什么MSVC會為看似正確的代碼生成此警告,並激勵我在代碼中添加一些丑陋以保持代碼警告免費?

我相信條件中的常量表達式是完全有效的,特別是在基於編譯器優化代碼的能力的構造中。

此外,我沒有得到warning C4127的代碼warning C4127

void foo(unsigned bar)
{
    while (bar >= 0)
        ;
} 

我的問題是:不是warning C4127: conditional expression is constant完全沒用,它不會激發丑陋的代碼嗎? 這個警告是否有助於編寫更好的代碼?

我不認為它有用。 相反,有更多的誤報而不僅僅是do .. while(0)成語。 想想像這樣的結構

if(sizeof(long) == 8) { /* ... */ }
if(SOME_CONSTANT_MACRO) { /* ... */ }

前者不能被#if指令替換,后者可以,但是一些編碼風格指南更喜歡if版本,因為仍然對死代碼進行語法檢查(在其他平台或其他編譯時配置中沒有死)有些人發現閱讀起來更好。

警告(除了標准所要求的警告之外,其中大多數應被視為錯誤)通常是針對有效的代碼發出的,但可能會執行除預期之外的其他操作。 if(0)或類似的東西看起來很傻,但看起來不像“語法檢查這個否則死代碼”的意圖。 它可能會困擾讀者,但它是明確的,我不知道這是如何偶然發生的。

從目前給出的示例(我沒有自己的MSVC進行測試),似乎警告是針對C語言意義上的常量表達式(也就是說,不是可以是常量折疊但是語法上的東西不是一個常量表達式),所以它不是為if(array)或者if(function)發出的(例如gcc -Wall會發出警告,因為它可能是一個函數調用)。

while(0,0)更糟糕,在我看來,它會觸發一個警告,用gcc -Wall表示逗號操作符的左側沒有副作用,我可以想象這個警告偶爾會有用(通常是容易避免)。 while((void)0,0)此警告消失。

我建議關閉警告。

該條件表達式是恆定一定的警告可以是有用的。 在許多情況下,它可能指向代碼中的邏輯錯誤。

例如,如果您寫的內容如下:

if (x != NULL) { /* ... */ }

其中x是數組對象,表達式有效,但表達式x衰減到指向數組初始元素的指針,該元素不能是空指針。 我不知道是否會產生相同的錯誤,但它是同類錯誤的一個例子。

當然,它並不總是有用的。 在你的情況下,

do { /* ... */ } while (0)

idiom是編寫宏定義的最佳方式,該宏定義旨在用於需要語句的上下文中。 在另一個上下文中使用while (0)可能是一個邏輯錯誤[*]。

不幸的是,你的編譯器並不認為它是一個常見的習慣用法。 產生良好的警告是棘手的; 編譯器必須超越語言規則並推斷程序員的意圖。

在這種情況下,使用一些特定於編譯器的方法來抑制警告(只要它不破壞其他編譯器的代碼)可能是最好的方法。 在所有情況下使用命令行選項來抑制警告將是過度的; 你可能會錯過代碼中其他地方的有效警告。

顯然寫入while (0,0)而不是while (0)可以避免警告。 如果您這樣做,您應該添加一個注釋,清楚地表明它是您的特定編譯器的解決方法。 編譯器不應該警告while (0,0)或任何其他等效代碼沒有特殊原因。

[*]如果你想能夠使用break來跳出它,那么寫一個do { /* ... */ } while (0)語句是有意義的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM