Атой на массив символов с большим количеством целых - PullRequest
1 голос
/ 11 июня 2011

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

char data[64];
int a = 10;
std::string str = boost::lexical_cast<std::string>(a);
memcpy(data + 8*k,str.c_str(),sizeof(str.c_str()));   //k varies from 0 to 7

, и преобразование обратно в символы выполняется с помощью:

char temp[8];
memcpy(temp,data+8*k,8);
int a = atoi(temp);

В целом это работает нормально, но когдаЯ пытаюсь сделать это как часть проекта, включающего qt (версия 4.7), он прекрасно компилируется и выдает мне ошибки сегментации, когда он пытается читать с помощью memcpy ().Обратите внимание, что ошибка сегментации происходит только в цикле чтения, а не во время записи данных.Я не знаю, почему это происходит, но я хочу сделать это любым методом.

Итак, есть ли другие функции, которые я могу использовать, которые могут принимать массив символов, первый бит и последнийбит и преобразовать его в целое число.Тогда мне не пришлось бы использовать memcpy () вообще.Я пытаюсь сделать что-то вроде этого:

new_atoi(data,8*k,8*(k+1)); // k varies from 0 to 7

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

Ответы [ 2 ]

9 голосов
/ 11 июня 2011

Вы копируете только 4 символа (в зависимости от ширины указателя вашей системы).Это приведет к тому, что числа из 4+ символов, не равные NULL, будут завершены, что приведет к тому, что на входе atoi

 sizeof(str.c_str()) //i.e. sizeof(char*) = 4 (32 bit systems)

должны появиться строки с пробелами

 str.length() + 1

.1007 *

Только STL:

make_testdata(): просмотреть все пути вниз

Почему бы вам не использовать потоки ...?

#include <sstream>
#include <iostream>
#include <algorithm>
#include <iterator>
#include <string>
#include <vector>

int main()
{
    std::vector<int> data = make_testdata();

    std::ostringstream oss;
    std::copy(data.begin(), data.end(), std::ostream_iterator<int>(oss, "\t"));

    std::stringstream iss(oss.str());

    std::vector<int> clone;
    std::copy(std::istream_iterator<int>(iss), std::istream_iterator<int>(),
              std::back_inserter(clone));

    //verify that clone now contains the original random data:
    //bool ok = std::equal(data.begin(), data.end(), clone.begin());

    return 0;
}

Вы могли бы сделать это намного быстрее в простом C с atoi / itoa и некоторыми хитростями, но я считаю, что вы должны использовать двоичную передачу (см. Boost Spirit Karma и protobuf для хороших библиотек) если вам нужна скорость.

Boost Karma / Qi:

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>

namespace qi=::boost::spirit::qi;
namespace karma=::boost::spirit::karma;

static const char delimiter = '\0';

int main()
{
    std::vector<int> data = make_testdata();

    std::string astext;
//  astext.reserve(3 * sizeof(data[0]) * data.size()); // heuristic pre-alloc
    std::back_insert_iterator<std::string> out(astext);

    {
        using namespace karma;
        generate(out, delimit(delimiter) [ *int_ ], data);
    //  generate_delimited(out, *int_, delimiter, data); // equivalent
    //  generate(out, int_ % delimiter, data); // somehow much slower!
    }

    std::string::const_iterator begin(astext.begin()), end(astext.end());
    std::vector<int> clone;
    qi::parse(begin, end, qi::int_ % delimiter, clone);

    //verify that clone now contains the original random data:
    //bool ok = std::equal(data.begin(), data.end(), clone.begin());

    return 0;
}

Если вы хотите вместо этого выполнять двоичную сериализацию, независимую от архитектуры, вы бы использовали эту крошечную адаптацию, создающуювещи в миллиард раз быстрее ( см. тест ниже ... ):

karma::generate(out, *karma::big_dword, data);
// ...
qi::parse(begin, end, *qi::big_dword, clone);

Повышение сериализации

Наилучшей производительности можно достичь, когдаиспользование ускоренной сериализации в двоичном режиме:

#include <sstream>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/vector.hpp>

int main()
{
    std::vector<int> data = make_testdata();

    std::stringstream ss;
    {
        boost::archive::binary_oarchive oa(ss);
        oa << data;
    }

    std::vector<int> clone;
    {
        boost::archive::binary_iarchive ia(ss);
        ia >> clone;
    }

    //verify that clone now contains the original random data:
    //bool ok = std::equal(data.begin(), data.end(), clone.begin());

    return 0;
}

Testdata

(, общий дляВсе версии выше )

#include <boost/random.hpp>

// generates a deterministic pseudo-random vector of 32Mio ints
std::vector<int> make_testdata()
{
    std::vector<int> testdata;

    testdata.resize(2 << 24);
    std::generate(testdata.begin(), testdata.end(), boost::mt19937(0));

    return testdata;
}

Тесты

Я тестировал его по

  • , используя входные данные 2<<24 (33554432) случайных целых чисел
  • не отображает вывод (мы не хотим измерять производительность прокрутки нашего терминала)
  • приблизительные значения времени были
    • Версия только для STL не так уж плоха на самом деле в 12.6s
    • Текстовая версия Карма / Ци пробежала в 18 с 5,1 с , благодаря подсказке Арлена в generate_delimited:)
    • Двоичная версия кармы / ци (big_dword) всего за 1.4 с ( примерно 12x в 3-4 раза быстрее )
    • Повышенная сериализация занимает около 0,8 с (или при замене текстовых архивов вместо двоичных файлов, около 13 с)
2 голосов
/ 13 июня 2011

Нет абсолютно никаких причин, чтобы текстовая версия Карма / Ци была медленнее, чем версия STL. Я улучшил @sehe реализацию текстовой версии Карма / Ци, чтобы отразить это утверждение.

Следующая Boost Karma / Qi текстовая версия более чем в в два раза быстрее , чем версия STL:

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/random.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>

namespace ascii = boost::spirit::ascii;
namespace qi = boost::spirit::qi;
namespace karma = boost::spirit::karma;
namespace phoenix = boost::phoenix;


template <typename OutputIterator>
void generate_numbers(OutputIterator& sink, const std::vector<int>& v){

  using karma::int_;
  using karma::generate_delimited;
  using ascii::space;

  generate_delimited(sink, *int_, space, v);
}

template <typename Iterator>
void parse_numbers(Iterator first, Iterator last, std::vector<int>& v){

  using qi::int_;
  using qi::phrase_parse;
  using ascii::space;
  using qi::_1;
  using phoenix::push_back;
  using phoenix::ref;

  phrase_parse(first, last, *int_[push_back(ref(v), _1)], space);
}

int main(int argc, char* argv[]){

  static boost::mt19937 rng(0); // make test deterministic
  std::vector<int> data;
  data.resize(2 << 24);
  std::generate(data.begin(), data.end(), rng);

  std::string astext;
  std::back_insert_iterator<std::string> out(astext);
  generate_numbers(out, data);

  //std::cout << astext << std::endl;

  std::string::const_iterator begin(astext.begin()), end(astext.end());
  std::vector<int> clone;
  parse_numbers(begin, end, clone);

  //verify that clone now contains the original random data:
  //std::copy(clone.begin(), clone.end(), std::ostream_iterator<int>(std::cout, ","));

  return 0;
}
...