在 C++ 中从 uint8_t 转换为 long
converting from uint8_t to long in C++
我正在使用 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 的补码表示的问题,但我不能完全指出出了什么问题。有人能告诉我我在这里搞砸了什么吗?
谢谢
这里没有严重错误。一个不必要的演员表,但其他方面看起来不错。
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;
}
我正在使用 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 的补码表示的问题,但我不能完全指出出了什么问题。有人能告诉我我在这里搞砸了什么吗?
谢谢
这里没有严重错误。一个不必要的演员表,但其他方面看起来不错。
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;
}