C ++ - strcmp () не работает правильно? - PullRequest
4 голосов
/ 24 декабря 2009

Происходит что-то действительно странное: 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

Есть идеи, что происходит?

Заранее спасибо,

Onur

Редактировать 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 и, увидев эту строку, я выполнил все эти команды печати. ​​

Спасибо за ваш интерес,
Onur


ОК, я думаю, мне следует добавить еще одну вещь из моего кода. Это конструктор класса 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));
}

Ответы [ 12 ]

10 голосов
/ 24 декабря 2009

Похоже, что s - это указатель на массив в стеке, который перезаписывается при вызове новой функции, т.е. strcmp()

Что говорит отладчик после strcmp() вызова?

3 голосов
/ 22 марта 2011

В последних дистрибутивах Linux strcmp является символом типа STT_GNU_IFUNC . Это не поддерживается в последнем выпуске GDB (7.2 на момент написания). Это может быть причиной вашей проблемы, хотя в вашем случае возвращаемое значение выглядит подлинным.

1 голос
/ 25 декабря 2009

Как уже отмечали другие, почти невозможно, чтобы была проблема с strcmp.

Было бы лучше сократить проблемный код до абсолютного минимума, необходимого для воспроизведения проблемы (также включите инструкции по компиляции - какой компилятор, флаги, библиотека времени выполнения вы используете?). Скорее всего, вы обнаружите ошибку в процессе.

Если нет, вы получите большой кредит за обнаружение ошибки в одной из наиболее интенсивно используемых функций C; -)

1 голос
/ 25 декабря 2009

Я настоятельно рекомендую вам обнулить память перед началом ее использования. Я понимаю, что вывод GDB не имеет смысла, потому что вы проверяете, что это строки с нулевым символом в конце, но у меня было много string.h странных проблем с memset, bzero, calloc или чем-то еще, что вы хотите использовать.

В частности, обнулите память в конструкторе и буфере, который вы используете при чтении из файла.

1 голос
/ 25 декабря 2009

Единственный способ, которым вы когда-либо разберетесь в этом, - это запустить INTO strcmp с помощью отладчика.

1 голос
/ 24 декабря 2009

Учитывая, что вывод 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);
0 голосов
/ 25 декабря 2009

Пометьте собственную реализацию strcmp как встроенную и посмотрите, что произойдет ...

Из Изменения, новые функции и исправления серии GCC 4.3 для GCC 4.3.4:

"Во время оптимизации, направленной на обратную связь, обнаруживается ожидаемый размер блока, на котором работают функции memcpy, memset и bzero, и для случаев обычно используемых небольших размеров генерируется специализированный встроенный код."

Может быть, существуют некоторые другие связанные ошибки ...
Попробуйте выключить оптимизацию компилятора и / или функцию встраивания.

0 голосов
/ 25 декабря 2009

Спасибо, что все сэкономили время, чтобы ответить. Я написал свою собственную функцию сравнения строк, и она работала правильно в тот же момент, поэтому, очевидно, это проблема с strcmp (). Тем не менее, мой код все еще не работает, как я ожидаю. Но я буду просить о помощи только после того, как тщательно проанализирую ее. Спасибо.

0 голосов
/ 25 декабря 2009

Я настоятельно рекомендую сначала попытаться решить проблему с обычными строками STL - вы получите более чистый код и автоматизированное управление памятью, чтобы сосредоточиться на логике синтаксического анализатора. Только после того, как все работает, профилирование и доказывает, что манипулирование строками является узким местом производительности. Я бы посмотрел на все алгоритмы, используемые более подробно, затем на специализированных распределителях строк и, в крайнем случае, на ручной символ манипулирование массивом, в таком порядке.

0 голосов
/ 24 декабря 2009

Может быть, в одной из строк есть непечатный символ?

...