2011-09-16 39 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 :) 
}