2017-01-15 5 views
0

У меня есть это правило в файле yacc и отдельный файл C++ для действия правила. Но выход не ожидается, как показано с заявлением для печати ниже .Это правило в parser.y:yacc выводит неожиданные результаты

RecordItem : IdentifierList ':' TypeDenoter 
      { 
       char * result = declareRecordItem ($1 , $3); 
       $$ = result; 
       printf(" >>> inside RecordItem >> : %s\n",result); 
      } 
      ; 

и это функция «declareRecordItem» в main.cpp файле:

char* declareRecordItem(std::vector<char* >* varList , char* type){ 
    string stm = " "; 
    string identifier; 
    for(int i=0 ; i < varList-> size() ; i++) 
    { 
     identifier= string((*varList)[i]) ; 
     symtab[identifier] = string(type); 
     stm = stm + " " + string(type); 
    } 
    char * result = (char*)stm.c_str(); 
    printf(">>> inside declareRecordItem >> : %s\n",result); 

    return result ; 
} 

Результат в функции declareRecordItem верен, но когда он возвращается к правилу RecordItem, он ничего не производит, или иногда странные символы печатаются, как показано. Есть идеи !.

>>> inside declareRecordItem >> : i32 i32 
>>> inside RecordItem >> : 

ответ

0

Внутри declareRecordItem, вы создаете локальную переменную stm типа std::string, а затем возвращает значение: (char*)stm.c_str();

Однако stm перестает существовать, как только declareRecordItem возвращается, а указатель, возвращаемый stm.c_str(), относится к категории долгосрочных контрактов. Вполне возможно, что память, на которую теперь указывает, была повторно использована для хранения другого объекта.

Так что если вы хотите сохранить значение строки, вы должны либо

  • возвращение сама std::string, опираясь на РВО для повышения эффективности, или
  • создать и вернуть динамический объект (т.е. new std::string()) или
  • сделать копию C-стиля буфера строки (т.е. strdup(stm.c_str()))

В обоих последних двух случаях, вы будете нуждаться в т o вручную освободите копию, как только вы закончите с ней. В первом случае вам все равно нужно будет сделать копию базовой строки C, если вам нужно сохранить строку C.

Смешение операций с C и C++ сбивает с толку и приводит к загроможденному коду. Если вы собираетесь использовать C++, я рекомендую использовать std::string* всюду, хотя вы в конечном итоге используете тот же режим управления ручной памятью, что и в строках стиля C. Для компиляторов и других приложений с таблицами символов хороший компромисс заключается в том, чтобы поместить строку в таблицу символов (или карту неизменяемых имен символов) как можно скорее, даже в лексическом сканере, а затем передать ссылки на символы (или интернированные имена). Затем вы можете освободить весь репозиторий сохраненных строк в конце компиляции.

+0

Если я создаю динамический объект, он будет иметь тип указателя, i.e string * stm = new new std :: string(); , Но как добавить к нему так, как внутри цикла? ». –

+0

'* stm = * stm +" "+ ...' или просто '* stm + =" "+ ...' – rici

+0

Последний вопрос. как я могу преобразовать строку * в char *? –