在C ++中从uint8_t转换为long

时间:2015-08-25 23:03:31

标签: c++ char int long-integer twos-complement

我使用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的补码表示的一个问题,但我不能完全指出出错的地方。有人能告诉我在这里搞砸了什么吗?

由于

1 个答案:

答案 0 :(得分:3)

这里没有什么严重的错误。一个不必要的演员,但看起来不错。

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报告的结果。我的猜测是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;
}