2016-11-10 39 views
0

編輯:如果您在此基本上不同意Fedora指南,請解釋爲什麼這種方法比傳統循環更客觀。據我所知,即使CERT標準沒有對使用指針變量的指針進行任何說明。如何安全地使用指針索引數組

我目前正在讀Fedora Defensive Coding Guide,並提出以下建議:

始終保持你正在使用的數組的大小的軌道。 通常,如果讓指針超過數組的最後一個元素,並且通過從該指針中減去當前位置來計算剩餘的 元素的數量,則代碼更爲明顯。 替代方法,每次當位置 高級時更新單獨的變量,通常不太明顯正確。

這意味着對於一個給定陣列

int numbers[] = {1, 2, 3, 4, 5}; 

我不應該使用經典

size_t length = 5; 
for (size_t i = 0; i < length; ++i) { 
    printf("%d ", numbers[i]); 
} 

,而是這樣的:

int *end = numbers + 5; 
for (int *start = numbers; start < end; ++start) { 
    printf("%d ", *start); 
} 

或本:

int *start = numbers; 
int *end = numbers + 5; 
while (start < end) { 
    printf("%d ", *start++); 
} 
  1. 我的理解推薦是否正確?
  2. 我的實現是否正確?
  3. 最後2箇中哪個更安全?
+1

所有示例都有缺陷,因爲它們硬編碼數組的元素大小。除此之外,它是基於您使用哪一個的意見。 – 2501

+0

我認爲推薦使用類似於C++迭代器array.end()的值,比如'numbers_end'而不是'numbers + 5' ... –

+0

正如Alexei指出的,我們沒有看到任何**過去**你的例子中的指針。這些示例不會增加任何安全性。 – Djee

回答

2

您對文本內容的理解是正確的,您的實現也是如此。但關於建議的基礎,我認爲你很困惑安全正確

與使用索引不同的是,使用指針是更安全。這個觀點是,在推理代碼時,使用指針時更容易判定邏輯是正確的。安全是關於失敗模式:如果代碼不正確會引發什麼(引用陣列外部的位置)。正確性更爲重要:該算法可以完成所要做的事情。我們可能會說正確的代碼不需要安全。

這個推薦可能受到Andrew Koenig在Dr. Dobbs幾年前的系列影響。 How C Makes It Hard To Check Array Bounds。 Koenig說,

除了在很多情況下速度更快,指針有一個比數組更大的優勢:指向數組元素的指針是一個單一的值,足以唯一標識該元素。 [...]沒有指針,我們需要三個參數來確定範圍:數組和兩個索引。通過使用指針,我們可以只用兩個參數。

在C中,引用數組之外的位置,無論是通過指針還是索引,同樣是不安全的。編譯器不會把你趕出去(缺少對標準擴展的使用)。科尼格認爲,空氣中的球數較少,你有更好的方法來獲得正確的邏輯。

構造越複雜,他說得越明確。如果您想更好地說明差異,請雙擊strcat(3)。使用索引,在循環內有兩個名稱和兩個索引。可以將索引用於另一個的名稱。使用指針,這是不可能。你只有兩個指針。

1

我的理解推薦是否正確?
我的實施是否正確?

是的,所以它似乎。

當您有更復雜項目的數組時,有時會使用方法for(type_t start = &array; start != end; start++)。這主要是一個風格問題。

這種風格有時用於您已經有某些原因可用的開始和結束指針。或者在您對尺寸沒有真正興趣的情況下,但只是想反覆比較數組的末尾。例如,假設您有一個帶有開始指針和結束指針的環形緩衝區ADT,並且要遍歷所有項目。

這種做循環的方式實際上就是爲什麼C顯式允許指針指向數組的一個邊界之外的指針,您可以設置一個結束指針指向數組之後的一個條目,而不會調用未定義的行爲只要該項目未被取消參考)。 (這與C++中STL迭代器使用的方法非常相似,儘管在C++中有更多的基本原理,因爲它具有運算符過載。例如,C++中的iterator++不一定給出在C++中相鄰分配的項目下一個存儲單元。例如,可以使用迭代器遍歷鏈表ADT,其中++將在行後面翻譯爲node->next)。

但是,聲稱這種形式始終是首選的只是主觀的廢話。特別是當你有一個整數的數組,並知道大小。你的第一個例子是C中最可讀的循環形式,因此在任何可能的情況下總是首選。

在一些編譯器/系統上,第一種形式也可以比第二種形式提供更快的代碼。指針算術可能會在某些系統上給出較慢的代碼。 (我想第一種形式可能會在某些系統上提供更快的數據高速緩存訪​​問,但我必須通過一些編譯器大師驗證這一假設。)

最後2箇中哪個更安全?

兩種形式都沒有比另一種更安全。否則會主觀意見。聲明「......通常不太明顯」是無稽之談。

選擇哪種風格因個案而異。總的來說,你們鏈接的那些「Fedora」指南似乎包含大量有問題的代碼,可疑的規則和公然的意見。看起來更像是有人想炫耀各種C技巧,而不是認真編寫編碼標準。總的來說,它聞起來像「Linux內核指南」,我不建議閱讀。

如果您想爲專業人士提供嚴謹的編碼標準,請使用CERT-CMISRA-C

+0

感謝您的信息。我指的是Fedora指南,完全是因爲CERT沒有提及數組索引,所以我猜這兩種方法都很安全 – AdHominem

+0

是否有任何免費下載的MISRA C?它似乎只是平裝和8歲。它仍然有用嗎? – AdHominem

+0

@AdHominem C語言已超過40歲:)無論如何,MISRA-C的最新版本是2012年以後添加的2個附錄。它是一個積極更新的標準,非常相關,儘管它不支持C11(大多數編譯器都不支持)。你可以購買它的PDF格式。 – Lundin