c++中的到字节转换

  • 本文关键字:转换 到字节 c++ c++
  • 更新时间 :
  • 英文 :


我尝试制作一个c++函数,该函数接收一个指针,然后返回一个指向表示字节的char数组的指针

char* toBytes(void* src, int byteSize) {
char convertedToBytes[byteSize];
memcpy(&convertedToBytes, src, byteSize);
return _strdup(convertedToBytes);
}

尽管当使用它并检查每个字符时,我看到输出是3 0 ffffffffff d ffffffoff d而不是3 0 0,但以下是完整的代码:

int32_t i_lengthOfCommand = 3;
char *s_lengthOfCommand = toBytes(&i_lengthOfCommand);
printf("%x %x %x %x", s_lengthOfCommand[0], s_lengthOfCommand[1], s_lengthOfCommand[2], s_lengthOfCommand[3]);

标准输出:3 0 ffffffff d fffffffff d

PS:我知道不支持big/little-endian

我建议使用std::string:

template<class T>
std::string toBytes(const T& src) {
return {reinterpret_cast<const char*>(&src),
reinterpret_cast<const char*>(&src) + sizeof src};
}

或者,如果您不需要更改内容,则使用std::string_view:

template<class T>
std::string_view toBytes(const T& src) {
return {reinterpret_cast<const char*>(&src),
sizeof src};
}

然后,您可以与send()等一起使用:

auto res = toBytes(i_lengthOfCommand);
send(sockfd, res.data(), res.size(), flags);

您不需要函数。如果不将数组的大小显式传递给函数,指针的长度永远无法正确推断。

只需使用石膏即可获得您想要的:

int32_t i_lengthOfCommand = 3;
char *s_lengthOfCommand = reinterpret_cast<char*>(&i_lengthOfCommand);
printf("%x %x %x %x", s_lengthOfCommand[0], s_lengthOfCommand[1], s_lengthOfCommand[2], s_lengthOfCommand[3]);

在一个小端序系统上,比如所有的英特尔芯片,上面的代码都会打印出来3 0 0 0。将首先打印i_ lengthOfCommand中的最低有效字节值。

在Big Endian系统上,它会打印0 0 0 3

如果您的意图是支持endian,请查看boost endian库:https://www.boost.org/doc/libs/1_71_0/libs/endian/doc/html/endian.html

以下是强制执行big-endian的示例https://www.boost.org/doc/libs/1_71_0/libs/endian/doc/html/endian.html#buffers_example

一般来说,你想建立一个库用例,然后进行必要的转换,而不是建立一个通用库,然后发现它不适合你的用例。如果只是endian支持,那么提升endian比滚动自己的更简单。

这里有很多错误

char* toBytes(void* src, int byteSize) {
char convertedToBytes[sizeof(src)];
memcpy(&convertedToBytes, src, byteSize);
return _strdup(convertedToBytes);
}

第一个

char convertedToBytes[sizeof(src)];

将总是分配4或8个字节,这取决于32位还是64位可执行。你无法从指向数组的指针中找到数组的大小。我的意思是,你已经将长度作为第二个参数传入

接下来为什么你有一个中间缓冲无论如何

memcpy(&convertedToBytes, src, byteSize);

但这是不正确的,无论如何,你需要

memcpy(convertedToBytes, src, byteSize);

然后将字节复制到堆中。但是strdup需要一个以null结尾的字符串,不能保证你的void*指向这样一个东西

你的函数不会"转换"任何东西,它所做的只是一个非常复杂的memcpy

整个东西可以被取代

char* toBytes(void* src, int byteSize) {
return (char*)src;
}

好的,让我们看看。

char* toBytes(void* src) {
char convertedToBytes[sizeof(src)];
memcpy(&convertedToBytes, src, sizeof(src));
return _strdup(convertedToBytes);
}

让我们从这个开始。CCD_ 8被签名。所以有些值是正的,有些值是负的。您应该使用unsigned char

你方法的最后一行很麻烦。它假设你有一个C风格的字符串,但你没有。

C样式字符串是一系列字符,末尾有一个字符是零字节。字符以ASCII表示。strdup()调用将返回垃圾,因为数组中有随机的非ASCII数据。

您可能使用64位体系结构,所以您的数组有8个字节长,不能保证有一个空字节。但如果地址足够低,则有一个LEADING空字节。

假设src指向地址0x00 00 00 00 12 34 56 78。我加了空格来表明观点。这是八个字节及其十六进制值。

所以现在你的strdup将看到领先的00,并说;哦,绳子的尽头;。当然,你的地址可能比这个例子复杂得多,它可能是8个非零字节,或者介于两者之间的任何字节。不好。

strdup()是错误的方法。你要做的就是边走边构建一个字符串。最简单的方法是使用各种数字到字符串的方法之一。例如:

std::string result;
char holder[10];
for (int index = 0; index < sizeof(src); ++index) {
sprintf(holder, "%0x", convertedToBytes[index]);
result += holder;
}

然后,如果您的方法返回std::string,则可以返回结果。

您可以考虑更现代的东西(C++17之后(。我可能会使用std::array做一些类似的事情。

template<typename T>
std::array<std::byte, sizeof(T)> toBytes(T const& t)
{
std::array<std::byte, sizeof(T)> a;
std::copy((std::byte const*)&t, (std::byte const*)(&t + 1), a.data());
return a;
}
in main()
{
int32_t i_lengthOfCommand = 3;
auto s_lengthOfCommand = toBytes(i_lengthOfCommand);
printf("%x %x %x %x", int(s_lengthOfCommand[0]), int(s_lengthOfCommand[1]), int(s_lengthOfCommand[2]), int(s_lengthOfCommand[3]));
}

使用std::array的好处是,您不会有悬挂指针或内存泄漏的风险,它可以记住其长度,并且易于迭代。例如:

for(auto b: s_lengthOfCommand)
std::cout << std::hex << b << ' ';
std::cout << 'n';

最新更新