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:OK、コードからもう1つ追加する必要があると思います。これは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>
        }
}

デバッガーでprintコマンドを実行する場所は最後です

throw UNKNOWN_WORD;

指図。つまり、次はGDBを踏んでいて、この行を見た後、これらすべての印刷コマンドを実行しました。

興味を持ってくれてありがとう、
オヌール


OK、コードからもう1つ追加する必要があると思います。これは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

GDB の出力から考えられる唯一の原因は、strcmp() にバグがあることです。

基本的に、strcmp が行うことを GDB で行いました。文字ごとに、両方がゼロになるまで (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 に問題があることはほぼ不可能です。

問題のあるコードを、問題を再現するために必要な最小限にまで削ぎ落とすのが最善です (コンパイル方法の説明も含めてください - どのコンパイラ、フラグ、ラ​​ンタイム ライブラリを使用していますか?)。ほとんどの場合 、プロセスでバグが見つかります。

そうでない場合は、最も頻繁に使用される C 関数の 1 つでバグを発見したことで、多くの功績が認められます ;-)

于 2009-12-24T22:40:29.160 に答える
1

これを理解する唯一の方法は、デバッガーで strcmp にステップ インすることです。

于 2009-12-24T21:15:36.620 に答える
1

使用を開始する前に、メモリをゼロにすることを強くお勧めします。nullで終了する文字列であることを確認しているため、GDB出力が意味をなさないことはわかっていますが、多くのstring.hの奇妙な問題は、memset、bzero、callocなど、使用したいもので解決しました。

具体的には、ファイルから読み取るときに使用するコンストラクターとバッファーのメモリをゼロにします。

于 2009-12-24T21:45:33.673 に答える
0

strlen(s[i])と は同じものをstrlen(grammar->symbols_from_int[107])返しますか?

iまた、これが問題だとは想像できませんが、奇妙なことが起こっていないことを確認するだけでなく、定数値を使用できますか?

于 2009-12-24T20:09:19.950 に答える
0

2 つの文字列のサイズが同じでない可能性があります。

于 2009-12-24T20:10:31.760 に答える
0

自分の strcmp 実現をインラインとしてマークし、何が起こるか見てみましょう ...

GCC 4.3 リリース シリーズの変更、新機能、およびGCC 4.3.4 の修正から:

「フィードバック指向の最適化中に、memcpy、memset、および bzero 関数が動作する予想ブロック サイズが検出され、一般的に使用される小さなサイズの場合、特殊なインライン コードが生成されます。」

他にも関連するバグが存在する可能性があります...
コンパイラの最適化または関数のインライン化をオフにしてみてください。

于 2009-12-25T08:10:53.143 に答える
0

最初に通常の STL 文字列を使用して問題を解決することを強くお勧めします。よりクリーンなコードと自動化されたメモリ管理が得られるため、パーサー ロジックに集中できます。物事が機能し、プロファイリングが文字列操作がパフォーマンスのボトルネックであることを証明した後でのみ、使用されるすべてのアルゴリズムをより詳細に調べ、次に特殊な文字列アロケーターを調べ、最後の手段として手動の文字配列操作をこの順序で調べます。 .

于 2009-12-24T21:27:32.133 に答える
0

時間を割いて回答してくださった皆様、ありがとうございました。独自の文字列比較関数を作成しましたが、同じ時点で正しく機能したため、明らかに strcmp() の問題です。それにもかかわらず、私のコードはまだ期待どおりに機能しません。しかし、私はそれを徹底的に分析した後にのみ、そのための助けを求めます. ありがとう。

于 2009-12-24T22:15:40.133 に答える
-1

文字列の 1 つに印刷できない文字が含まれている可能性がありますか?

于 2009-12-24T20:13:38.150 に答える