我尝试制作一个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';