2011-09-16 53 views
2

這是一個函數,用於檢查用戶輸入到我正在編譯的解釋器/解析器中的函數的名稱,並將其與函數數組進行比較,並執行相應的C++函數。只要用戶輸入正確的函數名稱,它就可以正常工作,但如果用戶輸入的名稱沒有功能,解釋程序就會以一些無法解釋的運行時錯誤結束,即使我將其編程爲打印「未定義的函數」,然後繼續解析循環:C++解析器源代碼中的不明原因錯誤

void parser::eval_cmd(std::string& exp, pro::command fset[]) 
{ 
    expr = exp; 
    exp_ptr = (char*) expr.c_str(); 

    bool found = false; 

    for (int i = 0; i < (int)sizeof(fset); i++) 
    { 
     if (fset[i].check(expr)) 
     { 
      found = true; 
      exp_ptr = (char*)expr.c_str() + (fset[i].name.size() - 1); 
      if (fset[i].cmd) 
       fset[i].cmd(eval_args()); 
      break; 
     } 

    } 

    if (!found) err::show(err::UNDEFINED); 
} 

我究竟做錯了什麼?

+0

由於無法解釋的錯誤,你的意思是'err :: show(err :: UNDEFINED);'已經執行了嗎? – Shahbaz

+0

@Shahbaz我之所以稱之爲「無法解釋的」錯誤的原因是爲了讓人們明白我不是在談論自己的錯誤。 – ApprenticeHacker

+0

expr = exp;這行不是對原始字符串進行深層複製(std :: string實現引用計數)。比你拋棄了底層char *的代價。有很好的理由爲什麼c_str()返回一個const char *。你不應該以這種方式使用std :: string。 –

回答

7

你在做錯的是(int)sizeof(fset)。這給你一個指針的大小,以字節爲單位,而不是傳入的fset數組中元素的數量。

您需要通過使用std::容器而不是數組,或者通過NULL終止數組來確定數組中有多少元素,或許可以通過傳遞另一個arg來進行確定。

例如,稍微改變你的函數定義:

void parser::eval_cmd(std::string& exp, const std::vector<pro::command>& fset) 
{ 
    ... 

    for (int i = 0; i < fset.size(); i++) 
    { 
     ... 

的代碼的其餘部分不變。


編輯:我最好的建議是使用 std::map<string, pro::command>,並允許 map管理查找算法,或者 std::vector<pro::comand>和使用上述算法不變。你可以測量內存的性能,但我認爲 vector over array的唯一開銷是 new ed數組通過靜態數組的開銷。

如果你得出的結論不使用標準容器,這裏是我的第二個最佳忠告:

void parser::eval_cmd(std::string& exp, pro::command fset[], size_t count) 
{ 
    ... 

    for (int i = 0; i < count; i++) 
    { 

想必調用者知道(或能夠確定)FSET數組中元素的個數。 (見Can this macro be converted to a function?尋求幫助。)

+0

+1。這個問題被標記爲「C++」,但它是非常類似C的代碼。使用STL容器可能會有所幫助。 – Raedwald

+0

+1。感謝它正在完美工作。但我試圖避免STL(和其他內存消耗功能和庫)的原因是它可能會導致解釋器的開銷。你有什麼建議?這只是不必要的優化,還是會導致後續的性能問題? – ApprenticeHacker

+0

@IntermediateHacker你真的認爲自制代碼比標準庫算法更快嗎?你是否描述過它? –

2

我看到一個直接的錯誤,雖然沒有看到更多的代碼,但我不知道這些症狀可能是什麼。你是循環控制 條件使用sizeof(fset)fset是一個指針,所以值將 總是相同的(通常4或8,這取決於你是否在32 位或64位模式)。我fset有更少的成員,那麼你將有 未定義的行爲,如果它有更多,你不會檢查任何 後來的功能。

我的建議是將std::map用於fset,並完全跳過 循環。

+0

對於'std :: map '+1。很棒的選擇。 –

0
..., pro::command fset[]) 

相當於

..., pro::command *fset) 

所以,當你這樣做,sizeof(fset),它計算sizeof(command*)而不是實際sizeof(command)。如果你不知道的fset[]大小,那麼你可以寫一個template包裝:

template<unsigned int SIZE> // <--- finds the sizeof fset 
void parser::eval_cmd_array(std::string& exp, pro::command (&fset)[SIZE]) 
{ 
    void parser::eval_cmd(exp, fset, SIZE); // <--- pass the size as 3rd param 
} 

現在你已經得到了你原有的功能數組的大小;

void parser::eval_cmd(std::string& exp, pro::command fset[], unsigned int sizeof_fset) 
{               //^^^^^^^^^^^^^^^^^^^^^^^^^ 
//... 
    for (unsigned int i = 0; i < sizeof_fset; i++) 
//... ^^^^^^^^ let it be unsigned :) 
}