5

发生了一些非常奇怪的事情:虽然两个字符串完全相同,但 strcmp() 返回 -1。以下是调试器 (gdb) 输出的片段:

(gdb) print s[i][0] == grammar->symbols_from_int[107][0]
$36 = true
(gdb) print s[i][1] == grammar->symbols_from_int[107][1]
$37 = true
(gdb) print s[i][2] == grammar->symbols_from_int[107][2]
$38 = true
(gdb) print s[i][3] == grammar->symbols_from_int[107][3]
$39 = true
(gdb) print s[i][4] == grammar->symbols_from_int[107][4]
$40 = true
(gdb) print s[i][5] == grammar->symbols_from_int[107][5]
$41 = false
(gdb) print grammar->symbols_from_int[107][4]
$42 = 0 '\0'
(gdb) print s[i]
$43 = (char * const&) @0x202dc50: 0x202d730 "Does"
(gdb) print grammar->symbols_from_int[107]
$44 = (char * const&) @0x1c9fb08: 0x1c9a062 "Does"
(gdb) print strcmp(s[i],grammar->symbols_from_int[107])
$45 = -1

知道发生了什么吗?

提前致谢,

奥努尔

编辑 1:这是我的代码的一些片段:

# include <unordered_map>       // Used as hash table
# include <stdlib.h>
# include <string.h>
# include <stdio.h>
# include <vector>

using namespace std;
using std::unordered_map;
using std::hash;

struct eqstr
{
  bool operator()(const char* s1, const char* s2) const
  {
    return strcmp(s1, s2) == 0;
  }
};

...
<some other code>
...

class BPCFG {

  public:

        char *symbols;  // Character array holding all grammar symbols, with NULL seperating them.
        char *rules;    // Character array holding all rules, with NULL seperating them.

        unordered_map<char *, int , hash<char *> , eqstr> int_from_symbols; // Hash table holding the grammar symbols and their integer indices as key/value pairs.
...
<some other code>
...

vector<char *> symbols_from_int;        // Hash table holding the integer indices and their corresponding grammar symbols as key/value pairs.
void load_symbols_from_file(const char *symbols_file);
}

void BPCFG::load_symbols_from_file(const char *symbols_file) {
        char buffer[200];
        FILE *input = fopen(symbols_file, "r");
        int symbol_index = 0;
        while(fscanf(input, "%s", buffer) > 0) {
                if(buffer[0] == '/')
                        strcpy(symbols + symbol_index, buffer+1);
                else
                        strcpy(symbols + symbol_index, buffer);
                symbols_from_int.push_back(symbols + symbol_index);
                int_from_symbols[symbols+symbol_index] = symbols_from_int.size()-1;
                probs.push_back(vector<double>());
                hyperprobs.push_back(vector<double>());
                rules_from_IntPair.push_back(vector<char *>());
                symbol_index += strlen(symbols+symbol_index) + 1;
        }


        fclose(input);
}

最后一个函数(BPCFG::load_symbols_from_file)似乎是我在整个代码中修改symbols_from_int 的唯一函数。如果您需要更多代码,请告诉我。我没有把所有东西都放好,因为它有数百行。

编辑 2:好的,我想我应该从我的代码中再添加一件事。这是 BPCFG 类的构造函数:

BPCFG(int symbols_length, int rules_length, int symbol_count, int rule_count):
   int_from_symbols(1.5*symbol_count),
   IntPair_from_rules(1.5*rule_count),
   symbol_after_dot(10*rule_count)
{
    symbols = (char *)malloc(symbols_length*sizeof(char));
    rules = (char *)malloc(rules_length*sizeof(char));
}

编辑3:这是错误点路径上的代码。它是不可编译的,但它显示了代码的单步执行位置(我在调试器中使用 next 和 step 命令检查了代码确实遵循这条路线):

BPCFG my_grammar(2000, 5500, 194, 187);
my_grammar.load_symbols_from_file("random_50_1_words_symbols.txt");
<some irrelevant code>
my_grammar.load_rules_from_file("random_50_1_words_grammar.txt", true);
<some irrelevant code>
my_grammar.load_symbols_after_dots();

BPCFGParser my_parser(&my_grammar);
BPCFGParser::Sentence s;

// (Sentence is defined in the BPCFGParser class with
// typedef vector<char *> Sentence;)

Edge e;
try {
        my_parser.parse(s, e);
}
catch(char *e) {fprintf(stderr, "%s", e);}

void BPCFGParser::parse(const Sentence & s, Edge & goal_edge) {

        /* Initializing the chart */

        chart::active_sets.clear();
        chart::passive_sets.clear();
        chart::active_sets.resize(s.size());
        chart::passive_sets.resize(s.size());

        // initialize(sentence, goal);

        try {
                initialize(s, goal_edge);
        }
        catch (char *e) {
                if(strcmp(e, UNKNOWN_WORD) == 0)
                        throw e;
        }
<Does something more, but the execution does not come to this point>
}

void BPCFGParser::initialize(const Sentence & s, Edge & goal_edge) {
        // create a new chart and new agendas
        /* For now, we plan to do this during constructing the BPCFGParser object */

        // for each word w:[start,end] in the sentence
        //   discoverEdge(w:[start,end])

        Edge temp_edge;

        for(int i = 0;i < s.size();i++) {
                temp_edge.span.start = i;
                temp_edge.span.end = i+1;
                temp_edge.isActive = false;
                /* Checking whether the given word is ever seen in the training corpus */
                unordered_map<char *, int , hash<char *> , eqstr>::const_iterator it = grammar->int_from_symbols.find(s[i]);
                if(it == grammar->int_from_symbols.end())
                        throw UNKNOWN_WORD;
                <Does something more, but execution does not come to this point>
        }
}

我在调试器中运行打印命令的地方是最后一个

throw UNKNOWN_WORD;

命令。我的意思是,我在 GDB 上使用 next 并在看到这一行之后,我运行了所有这些打印命令。

感谢您的关注,
奥努尔


好的,我想我应该从我的代码中再添加一件事。这是 BPCFG 类的构造函数:

BPCFG(int symbols_length, int rules_length, int symbol_count, int rule_count):
   int_from_symbols(1.5*symbol_count),
   IntPair_from_rules(1.5*rule_count),
   symbol_after_dot(10*rule_count)
{
    symbols = (char *)malloc(symbols_length*sizeof(char));
    rules = (char *)malloc(rules_length*sizeof(char));
}
4

12 回答 12

10

这听起来像是s一个指向堆栈上的数组的指针,一旦调用新函数就会被覆盖,即strcmp()

调试器在调用后说它们是strcmp()什么?

于 2009-12-24T20:30:28.147 回答
3

在最近的 Linux 发行版中,strcmp 是STT_GNU_IFUNC类型的符号。GDB 的最新版本(撰写本文时为 7.2)不支持此功能。这可能是您的问题的原因,尽管在您的情况下返回值看起来是真实的。

于 2011-03-22T15:25:55.367 回答
1

正如其他人指出的那样,strcmp 几乎不可能出现问题。

最好将有问题的代码剥离到重现问题所需的绝对最低限度(还包括有关如何编译的说明——您使用的是哪个编译器、标志、运行时库?)。您很可能 在此过程中发现错误。

如果没有,您将因在使用最频繁的 C 函数之一中发现错误而获得很多赞誉;-)

于 2009-12-24T22:40:29.160 回答
1

鉴于 GDB 输出我能看到的唯一可能原因是 strcmp() 被窃听。

您基本上在 GDB 中做了 strcmp 所做的事情:比较每个字符的字符,直到两者都为零(在 4 处)。

你能试试print strcmp("Does", "Does");吗?


编辑:也尝试:

print stricmp(s[i], grammar->symbols_from_int[107], 1);
print stricmp(s[i], grammar->symbols_from_int[107], 2);
print stricmp(s[i], grammar->symbols_from_int[107], 3);
print stricmp(s[i], grammar->symbols_from_int[107], 4);
print stricmp(s[i], grammar->symbols_from_int[107], 5);
于 2009-12-24T20:05:25.950 回答
1

唯一能解决这个问题的方法是使用调试器进入 strcmp。

于 2009-12-24T21:15:36.620 回答
1

我强烈建议您在开始使用之前将内存清零。我意识到 GDB 输出没有意义,因为您确实验证了它是一个以空字符结尾的字符串,但是我遇到了很多 string.h 奇怪的问题,使用 memset、bzero、calloc 或任何您想使用的东西都会消失。

具体来说,将构造函数中的内存和从文件读取时使用的缓冲区清零。

于 2009-12-24T21:45:33.673 回答
0

将你自己的 strcmp 实现标记为内联,看看会发生什么......

GCC 4.3 Release Series Changes, New Features, and Fixes for GCC 4.3.4 开始:

“在反馈导向优化过程中,会发现 memcpy、memset 和 bzero 函数操作的预期块大小,并且对于常用的小尺寸情况,会生成专门的内联代码。”

可能存在其他一些相关的错误...
尝试关闭编译器优化或/和函数内联。

于 2009-12-25T08:10:53.143 回答
0

strlen(s[i])strlen(grammar->symbols_from_int[107])返回一样吗?

另外,我无法想象这是问题所在,但您可以使用一个常量值而不是i仅仅确保不会发生奇怪的事情吗?

于 2009-12-24T20:09:19.950 回答
0

可能是两个字符串的大小不一样。

于 2009-12-24T20:10:31.760 回答
0

我强烈建议首先尝试使用常规 STL 字符串解决问题 - 您将获得更简洁的代码和自动内存管理,因此您可以专注于解析器逻辑。只有在事情正常工作并且分析证明字符串操作是性能瓶颈之后,我才会更详细地查看所有使用的算法,然后是专门的字符串分配器,并且 - 作为最后的手段 - 按此顺序进行手动字符数组操作.

于 2009-12-24T21:27:32.133 回答
0

感谢大家抽空回答。我编写了自己的字符串比较函数,它在同一点上正常工作,所以显然这是 strcmp() 的问题。尽管如此,我的代码仍然无法按预期工作。但是只有在我彻底分析之后,我才会请求帮助。谢谢。

于 2009-12-24T22:15:40.133 回答
-1

也许其中一个字符串中有不可打印的字符?

于 2009-12-24T20:13:38.150 回答