2011-11-10 231 views
1

我有以下C++代碼並在代碼上運行PC lint。預期表達式錯誤

問題1:

#if !WIN32 
#define ULONG_MAX 0xffffffff 
#endif 

上面的代碼如下

Error 26: Expected an expression, found 'WIN32'
Error 30: Expected an integer constant

如何解決上面的錯誤被拋出皮棉錯誤?

問題2:

const char CompanyName[] = "mycompany"; 

Error: Note 960: Violates MISRA Required Rule 8.5, no object/function definitions in header files

如何解決上面的錯誤?

問題3:

unsigned long m_ClientThreadId; 
m_ClientThreadId  = 0; 

Note 960: Violates MISRA Required Rule 10.1, Implicit conversion changes signedness

如何解決上面的錯誤?

+2

您需要提出更深入的問題,而不僅僅是「如何解決以上錯誤?」 「如何解決上述錯誤?」 「如何解決上述錯誤?」您還應該告訴我們您嘗試過什麼,或者如果您還沒有嘗試過,請閱讀並嘗試一些內容。 – BoltClock

回答

2

需要澄清幾點。例如,該行:

#if !WIN32 

實際上是很好定義的標準,並且可以合理利用 如果你的編譯器調用總是containt /DWIN32=1-DWIN32=0。 對於這個問題,該標準說,這是沒有定義的符號 宏擴展期間0更換,所以從來沒有任何問題 用線,除非一些其他公約規定的符號 將只能被定義在Windows機器上,但是它的值被定義爲 未指定;在這種情況下,你需要的是這樣的:

#ifndef WIN32 

最後,這取決於你爲 處理編譯器的依賴建立的約定。

在另一方面,應避免直接跟隨線, 因爲它定義了一個符號(ULONG_MAX),其在C和 C++標準中定義。這裏三線序應改爲:

#include <limits.h> 

至於第二個問題,我不知道如果錯誤不是MISRA規則的 小姐演繹。在C++中,const默認意味着內部鏈接 默認情況下:在標題中定義像這樣的符號將導致變量的多個實例化(在每個翻譯單元中具有不同的地址),但不會導致多個 定義的問題。而替代品也有其缺點。在這裏,我 更傾向於將用 宏替換變量定義:

#define CompanyName "mycompany" 

但宏有自己的問題。聲明符號extern和然後將其定義在一個(並且只有一個)源文件中是另一個 替代方案,但這涉及兩個語句,兩個不同的文件,其中(取決於變量所扮演的角色),可能是 更好。 (由名字來看,我不認爲這兩種說法 將是一個問題,但也有其他情況下,最好是 保持文本可見在頭)。把它當作你寫它 是也是一個可行的選擇,除非你的公司有嚴格的規則 反對它。

關於最後一點,表達式0的類型爲int,其中 已被簽名。你可以清楚地指定類型,0UL,但坦率地說,這 不應該是必要的:00,不分類型,雖然 有可能是要強制型,以確保 運算需要的情況下以某種方式放置,這不是其中之一。至於 的錯誤/警告,我懷疑這也是對MISRA規則 的誤解;隱式轉換會改變符號性,可能會產生問題,但不會在轉換內容時產生非常小的非負常數整數。因此,如果您需要將 附加到公司規則中,請寫下0UL,但請注意,這會帶來一些問題:基本上可靠的規則應用於 不適用的情況。

+0

+1爲答案,我很樂意給*另一個+1,這是帶着一些東西到傻瓜*。靜態分析儀可以幫助檢測潛在的問題,但這並不意味着他們所投訴的每一條線路都必須改變,只需要進行審查。 –

+0

@DavidRodríguez-dribeas沒有什麼可以阻止編程對靜態分析器有一點常識。通知可能導致值更改的隱式轉換非常好。通知可能影響表達式評估方式的隱式轉換。通知「0」的隱式轉換僅僅是噪聲,並降低了該工具的實用性。 –

+0

問題中提到的MISRA規則是MISRA C 2004規則,而不是MISRA C++規則。在C中,const並不意味着內部聯繫,所以在MISRA C中沒有考慮到這一點,所報告的違反8.5是有效的。規則10.1絕對禁止分配或初始化未經修改的0的無符號變量,這在Exemplar Suite和MISRA討論論壇中已經闡明。 PC-Lint在這裏不會誤解任何東西,它只是在做它的工作; MISRA警告不會提供,除非他們被要求並且很容易禁用。 –

4

第一:

你需要做這個:

#ifndef WIN32 
#define ULONG_MAX 0xffffffff 
#endif 

二:

不能定義在頭文件,否則同樣的符號將出現在多個編譯單元中。

你需要做的,而不是什麼,只是聲明在標題:

extern const char CompanyName[]; 

然後在一個模塊中,一旦定義它:

const char CompanyName[] = "mycompany"; 

三:

unsigned long m_ClientThreadId; 
m_ClientThreadId  = 0; 

這是不尋常的,但似乎0是一個有符號的常量。並將其分配給unsigned long具有隱式類型轉換。大多數編譯器實際上並未警告這一點。

+1

+1,但請注意,儘管爲2)建議的更改會使靜態分析器靜音,但我不會這樣做。原因是在C++常量中有* internal linkage *,所以在所有包含該頭的翻譯單元(TU)中重新定義常量不會導致錯誤。通過執行建議的更改,除了一個TU之外,變量將具有不完整的類型(數組的大小未知),並且會限制使用量(不是很多,但不能靜態獲取大小),替代方法是手動提供大小,但會增加維護成本:手動更新。 –

+0

我想另一種選擇是將定義放在標題中,但聲明它是靜態的。這將在編譯時防止重複符號,但會導致它的多個副本。另一種選擇是使用宏:'#define CompanyName「mycompany」'。 – Mysticial

+0

* extern * consts沒有內部鏈接,所以這很好。該數組的大小對於模板技巧和sizeof是很方便的,但是如果你不依賴它們,那麼它並不重要,定義應該肯定(哈哈)移出標題。 – spraff

0

對於第二個問題,這是一個頭文件中的行嗎?您應該一般不會在頭文件中定義變量,特別是如果該頭文件包含在多個文件中,因爲這將創建相同變量的兩個副本,並且會導致鏈接錯誤。

+0

這在C++中並不完全正確。常量具有內部鏈接(除非先前聲明爲具有外部鏈接),所以它不會觸發編譯錯誤,並且在大多數情況下,鏈接器將刪除重複的字符串。 –

1

對於第一個問題,我猜你應該使用

#ifndef WIN32 

代替

#if !WIN32 

因爲WIN32宏並不總是存在的,你需要檢查它的存在,而比它的「虛假」。

0

還有#if !defined(WIN32),但#ifndef WIN32更容易理解。

0

這些報告的錯誤都不是C++錯誤;他們是風格問題。

第一:

#if !WIN32 
#define ULONG_MAX 0xffffffff 
#endif 

這是合法的。在#if指令中,任何未定義的令牌都將被0替代。但如其他人所建議的那樣,編寫#ifndef WIN32的風格可能更好。

但是,真的,這整個事情可能是一個壞主意。 ULONG_MAX是在C標準頭部<limits.h>和C++標準頭部<climits>中定義的宏。

#include <climits> 

二:通過更換上述3條線路

const char CompanyName[] = "mycompany"; 

合法的,但一個壞主意。如果頭文件是來自不同翻譯單元的#include d,則會有多個CompanyName的定義。 (我不太確定C++規則對此有何看法。)請參閱Mysticial的答案。

三:

unsigned long m_ClientThreadId; 
m_ClientThreadId  = 0; 

這裏PC-lint時過於挑剔。是的,0(其類型爲int)到unsigned long的隱式轉換確實會更改簽名,但在這種情況下不會導致任何可能的問題。但是,您可以通過使用無符號long類型的字面量來避免警告:

unsigned long m_ClientThreadId; 
m_ClientThreadId  = 0UL;