gpt4 book ai didi

c++ - 如何在 C++ 中使用 Big Endian 格式而不是 Little Endian 来移动字节?

转载 作者:行者123 更新时间:2023-11-28 07:21:34 29 4
gpt4 key购买 nike

我正在使用 Java 和 Big Endian Byte Order 格式将字节数组值写入文件中。现在我需要从 C++ 程序中读取该文件...

我正在写入文件的字节数组由三个字节数组组成,如下所述-

short employeeId = 32767;
long lastModifiedDate = "1379811105109L";
byte[] attributeValue = os.toByteArray();

我正在将 employeeIdlastModifiedDateattributeValue 一起写入单个字节数组,并将生成的字节数组写入一个文件中,然后我将使用我的 C++ 程序从文件中检索字节数组数据,然后将其反序列化以从中提取 employeeIdlastModifiedDateattributeValue它。

下面是我的工作 Java 代码,它将字节数组值写入大端格式的文件中:

public class ByteBufferTest {

public static void main(String[] args) {

String text = "Byte Array Test For Big Endian";
byte[] attributeValue = text.getBytes();

long lastModifiedDate = 1289811105109L;
short employeeId = 32767;

int size = 2 + 8 + 4 + attributeValue.length; // short is 2 bytes, long 8 and int 4

ByteBuffer bbuf = ByteBuffer.allocate(size);
bbuf.order(ByteOrder.BIG_ENDIAN);

bbuf.putShort(employeeId);
bbuf.putLong(lastModifiedDate);
bbuf.putInt(attributeValue.length);
bbuf.put(attributeValue);

bbuf.rewind();

// best approach is copy the internal buffer
byte[] bytesToStore = new byte[size];
bbuf.get(bytesToStore);

writeFile(bytesToStore);

}

/**
* Write the file in Java
* @param byteArray
*/
public static void writeFile(byte[] byteArray) {

try{
File file = new File("bytebuffertest");

FileOutputStream output = new FileOutputStream(file);
IOUtils.write(byteArray, output);

} catch (Exception ex) {
ex.printStackTrace();
}
}
}

现在我需要使用下面的 C++ 程序从同一个文件中检索字节数组并将其反序列化以提取 employeeIdlastModifiedDateattributeValue从中。我不确定 C++ 方面的最佳方法是什么。以下是我到目前为止的代码:

int main() {

string line;

std::ifstream myfile("bytebuffertest", std::ios::binary);

if (myfile.is_open()) {

uint16_t employeeId;
uint64_t lastModifiedDate;
uint32_t attributeLength;

char buffer[8]; // sized for the biggest read we want to do

// read two bytes (will be in the wrong order)
myfile.read(buffer, 2);

// swap the bytes
std::swap(buffer[0], buffer[1]);

// only now convert bytes to an integer
employeeId = *reinterpret_cast<uint16_t*>(buffer);

cout<< employeeId <<endl;

// read eight bytes (will be in the wrong order)
myfile.read(buffer, 8);

// swap the bytes
std::swap(buffer[0], buffer[7]);
std::swap(buffer[1], buffer[6]);
std::swap(buffer[2], buffer[5]);
std::swap(buffer[3], buffer[4]);

// only now convert bytes to an integer
lastModifiedDate = *reinterpret_cast<uint64_t*>(buffer);

cout<< lastModifiedDate <<endl;

// read 4 bytes (will be in the wrong order)
myfile.read(buffer, 4);

// swap the bytes
std::swap(buffer[0], buffer[3]);
std::swap(buffer[1], buffer[2]);

// only now convert bytes to an integer
attributeLength = *reinterpret_cast<uint32_t*>(buffer);

cout<< attributeLength <<endl;

myfile.read(buffer, attributeLength);


// now I am not sure how should I get the actual attribute value here?

//close the stream:
myfile.close();
}

else
cout << "Unable to open file";

return 0;
}

我已经专门将存储 Java 端设置为 big-endian,这意味着我知道我猜每个字节属于哪里。那么如何在将字节移动到每个值的正确位置时对其进行编码呢?现在我正在将它编码为 little-endian 我猜这不是我想要的...

我在某个地方读到我可以在 C++ 中使用 ntoh 来反序列化字节数组。不确定 htons 是否会比我拥有的更好的解决方案目前?..

如果是,那么我不确定如何在我当前的 C++ 代码中使用它?

谁能看一下 C++ 代码,看看我能做些什么来改进它,因为我认为它看起来效率不高?有没有更好的方法来反序列化字节数组并在 C++ 端提取相关信息?

最佳答案

如果 Java 和 C++ 代码是由您开发的,那么最好使用 Google Protocol Buffer (https://developers.google.com/protocol-buffers/docs/overview) 而不是编写您自己的序列化器/反序列化器。

如果您真的想编写自己的实现,最好的方法是编写一个接收字节流作为参数(例如作为构造函数参数)的缓冲区类,并制定一些访问方法 readShort/readLong/readInt/readByte ...并且只交换需要的字节。

class ByteBuffer{
explicit ByteBuffer(uint8_t* byteStream, uint16_t streamLength);
uint8_t readUInt8(uint16_t readPos)const {return m_byteStream[readPos];} // no conversion needed
uint16_t readUInt16(uint16_t readPos)const {
const uint8_t byteCount = 2;
union{
uint16_t u16;
uint8_t u8[byteCount];
}tmp;
for(uint8_t i=0; i<byteCount; ++i){
tmp.u8[i] = readUInt8(readPos+i*8);
}
return ntohs(tmp.u16); // do conversion
}
...
}

这里缺少缓冲区后面的读取检查。如果您的代码应该是可移植的,那么您可以使用 ntohl/ntohs(请参阅:http://forums.codeguru.com/showthread.php?298741-C-General-What-do-ntohl%28%29-and-htonl%28%29-actually-do)。如果您自己交换字节,那么您的代码是不可移植的(只能在 Little-Endian 机器上运行)。如果您使用 ntoh,那么它也可以在这样的机器上运行。

为了方便起见,我还会编写一个包装类,您可以在其中直接读写您的字段(例如 employeeId):

class MyBuffer{
uint16_t readEmployeeId()const{return m_Buffer.readuint16(EmployeeId_Pos);}
....
static const uint16_t EmployeeId_Pos = 0;
....
}

关于c++ - 如何在 C++ 中使用 Big Endian 格式而不是 Little Endian 来移动字节?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19373922/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com