char — преобразование из uint8_t в long в Stack Overflow

Я использую map тип, чтобы имитировать память, т.е.

   map<long, uint8_t> memory

Где long это адрес и uint8_t байт памяти.

Теперь я могу написать (подписано) long печатать без проблем (думаю!)

void Memory::writeLong(const long address, const long value)
{
if (address < start || address + sizeof(long) > start + memorySize) {
cout << "Memory::readLong out of range" << endl;
throw "Memory class range error";
}

uint8_t *valRep = (uint8_t *) &value;
for (int i = 0; i < sizeof(long); i++)
{
contents[address + i] = *((uint8_t *)(valRep + i));
}
}

Но я не могу получить чтения для правильной обработки знака длинных позиций. Вот прочитанный код:

long Memory::readLong(const long address)
{
long retVal = 0;

if (address < start || address + sizeof(long) > start + memorySize) {
cout << "Memory::readLong out of range" << endl;
throw "Memory class range error";
}

uint8_t in[8];
for (int i = 0; i < sizeof(long); i++)
{
try {

in[i] =(uint8_t) contents.at(address + i) << (i * 8);
}
catch (const out_of_range& err)
{
contents[address] = 0;
}
}
memcpy(&retVal, in, 8);
return retVal;
}

Но это дает мне плохие результаты при попытке прочитать отрицательные числа, например: (в форме написано: читать)

-4: 1095216660732, -8: 1095216660728, -5: 1095216660731, -1: 1095216660735, -1224: 1095216660536

Хотя кажется, что правильно читать положительные числа. Это, похоже, проблема с представлением дополнения 2, но я не могу понять, что происходит не так. Может кто-нибудь сказать мне, что я здесь испортил?

Спасибо

2

Решение

Здесь нет ничего серьезного. Один ненужный актерский состав, но в остальном выглядит хорошо.

void Memory::writeLong(const long address, const long value)
{
if (address < start || address + sizeof(long) > start + memorySize) {
cout << "Memory::readLong out of range" << endl;
throw "Memory class range error";
}

uint8_t *valRep = (uint8_t *) &value;
for (int i = 0; i < sizeof(long); i++)
{
contents[address + i] = *((uint8_t *)(valRep + i));// don't need cast
}
}

Пара битов гадости в чтении:

long Memory::readLong(const long address)
{
long retVal = 0;

if (address < start || address + sizeof(long) > start + memorySize) {
cout << "Memory::readLong out of range" << endl;
throw "Memory class range error";
}

uint8_t in[8]; // should be uint8_t in[sizeof(retVal)];
// why sizeof(retVal) and not sizeof(long)
// someone could cut and paste to make the different typed
// versions and change only retVal. Might as well lock them
for (int i = 0; i < sizeof(long); i++) //nag nag, signed unsigned mismatch
{
try {

in[i] =(uint8_t) contents.at(address + i) << (i * 8);
// in[i] is 8 bits. << (i * 8) ensures all but the first byte are shifted
// out of byte range
}
catch (const out_of_range& err)
{
contents[address] = 0;
}
}
memcpy(&retVal, in, 8); // overruns retVal if retval is 32 bits. Use
// sizeof(retVal) again.
return retVal;
}

Так что это не может работать или генерировать результаты, о которых сообщалось. Я предполагаю, что у OP было что-то, что почти сработало, а затем начал крутиться вокруг, пытаясь это исправить, и все ухудшилось.

Как бы я это сделал:

Изменить: Оказывается, что наказание типа союзов является незаконным. Отстой, потому что я думаю, что это безопаснее и легче читать, чем указатель версии. Вероятно, единственная причина, по которой версия указателя не является незаконной, — это огромный объем законных случаев для приведения к байту.

Я также переместил блок try / catch за пределы цикла повторной сборки, потому что, как только вы читаете вне памяти, восстановление в значительной степени тост.

#include <iostream>
#include <map>

std::map<long, uint8_t> contents;
void writeLong(const size_t address, const long value)
{
/* not needed for test case
if (address < start || address + sizeof(long) > start + memorySize) {
cout << "Memory::readLong out of range" << endl;
throw "Memory class range error";
}
*/
uint8_t *valRep = (uint8_t *) &value;
for (size_t i = 0; i < sizeof(long); i++)
{
contents[address + i] = *(valRep + i);
}
}
long readLong(const size_t address)
{
// Verbotten!
//    union
//    {
//        long val;
//        uint8_t arr[sizeof(val)];
//    }retVal; // Ahhhrrrrrr! Here be endian nightmare!

long retVal;
uint8_t *valRep = (uint8_t *) &retVal;
// uglier, but legal. Consider using the no-punning version below

/* not needed for test case
if (address < start || address + sizeof(long) > start + memorySize) {
cout << "Memory::readLong out of range" << endl;
throw "Memory class range error";
}
*/
//   uint8_t in[sizeof(long)]; replaced by evil union abuse above
try
{
for (size_t i = 0; i < sizeof(long); i++)
{
// Not legal
//        retVal.arr[i] = contents.at(address + i) ;
*(valRep + i) = contents.at(address + i);
}
}
catch (const std::out_of_range& err)
{
retVal = 0;
}

//    memcpy(&retVal, in, sizeof(long)); replaced by evil union abuse above
// Not legal
//    return retVal.val;
return retVal;
}

void test(long val)
{
writeLong(0, val);
std::cout << "In " << val << " out " <<  readLong(0) << std::endl;
}

int main()
{
test(-4);
test(-8);
test(-5);
test(-1);
test(-1224);
test(0);
test(1);
test(0x7fffffff);
test(0x80000000);
}

Выход:

In -4 out -4
In -8 out -8
In -5 out -5
In -1 out -1
In -1224 out -1224
In 0 out 0
In 1 out 1
In 2147483647 out 2147483647
In -2147483648 out -2147483648

Я буду скучать по своему другу по типу ударов, но есть версии без ударов.

void writeLong(size_t address, long value)
{
// not needed for test case
//    if (address < start || address + sizeof(long) > start + memorySize) {
//        cout << "Memory::readLong out of range" << endl;
//        throw "Memory class range error";
//    }

for (size_t i = 0; i < sizeof(long); i++)
{ // note this only preserves the proper memory layout for little endian systems
contents[address + i] = (uint8_t)(value &0xFF);
value >>= 8;
}
}
long readLong(size_t address)
{
long retVal;

// not needed for test case
//    if (address < start || address + sizeof(long) > start + memorySize) {
//        cout << "Memory::readLong out of range" << endl;
//        throw "Memory class range error";
//    }
try
{
address += sizeof(long) - 1;
retVal = contents.at(address--);
for (size_t i = 0; i < sizeof(long) - 1; i++)
{ // this only works if the little endian memory layout is preserved
retVal <<= 8;
retVal += contents.at(address--);
}
}
catch (const std::out_of_range& err)
{
retVal = 0;
}
return retVal;
}
3

Другие решения


По вопросам рекламы [email protected]