当数据存储为uint8_t的向量时,如何传递'char* data'?
How to pass on 'char* data' when the data is stored as vector of uint8_t?
我有一个 class 定义如下:
class sco
{
private:
public:
vector<uint8_t> data;
sco(vector<uint8_t> data);
~sco();
};
构造函数所在位置:
sco::sco(vector<uint8_t> data) {
this->data = data;
}
然后我有一个声明如下的函数:
void send(unsigned& id, char* data, char len);
我的问题是我需要将一个sco成员的数据传递给它,但是类型和指针的不同让我很困惑。如果我有一个成员 newSco,里面有一些数据,将这个发送函数称为 send(someId, (char*)&(newSco.data.begin()), newSco.data.size() );
是否合理?请注意,函数 send 是针对微控制器的,它接受 char 类型,所以我不能改变它,我也不能改变 uint8_t 因为这是来自串行通信的类型。我已经浪费了 3 天多的时间试图将类型转换为相互的东西,只是为了将其反转回来,因为它破坏了一切。我放弃了,我将不再尝试操纵类型,因为我只是没有那种时间,只是需要它工作,即使这是不好的做法。我以为 uint8_t 和 char 的大小相同,所以没关系。
是的,在这种情况下将指针转换为 char* 是合理的。通常,由于 strict aliasing rules,您可能不会使用不同类型的指针引用相同的内存位置。但是,'char' 是一种特殊情况,因此允许转换。
您不应该将 uint32_t* 转换为 int32_t,例如,即使它在某些情况下可能有效。
编辑:如以下评论所述:从 uint8_t* 转换为 char* 可能没问题,从迭代器转换则不然。使用 .data() 而不是 .begin()。
这应该有效:
send(someId, static_cast<char*>(&newSco.data[0]), static_cast<char>(newSco.data.size()));
附加信息:
How to convert vector to array
What is the difference between static_cast<> and C style casting?
send(someId, (char*)&(newSco.data.begin()), newSco.data.size() )
你几乎已经掌握了它,但还不够。
原因如下:
begin()
给你一个迭代器。您正在获取该迭代器的地址,因此您处于间接级别。使用 C-style 转换掩盖了 type-related 编译错误。
我们可以写 (char*)&*(newSco.data.begin())
来取消引用迭代器,然后取第一个结果元素的地址。
但是如果容器是空的,这就很破了。你不能取消引用一个不存在的东西。
所以现在我们尝试:
send(someId, (char*)&newSco.data[0], newSco.data.size() )
不幸的是,如果容器为空,也不安全,因为.data[0]
也有效地取消引用了一个可能不存在的元素。有人认为隐含的 &*
"cancels it out",但这是有争议的,我从不相信。
如果你曾经迁移到 C++11 或更高版本,你可以使用完全安全的:
send(someId, (char*)newSco.data.data(), newSco.data.size() )
否则,坚持使用 &newSco.data[0]
,但当 newSco.data.size()
为零 时跳过整个 send
调用。怎么强调都不为过。
转换为 char*
本身是安全的;您可以以这种方式自由地将 uint8_t
s 解释为 char
s;有一个特殊的规则。这个模式我自己用过几次。
但是,如上所述,C-style 演员表并不理想。喜欢一个很好的重新解释。我还会添加一些 const
以备不时之需(如果您的 MC API 不允许,请跳过此步骤):
if (!newSco.data.empty())
{
send(
someId,
reinterpret_cast<const char*>(&newSco.data[0]),
newSco.data.size()
);
}
那里。华丽的。
最后一点,由于 API 的最后一个参数是 char
,我会考虑为容器大小设置一个上限。您可以 运行 循环中的函数,一次发送 CHAR_MAX
或 newSco.data.size()
字节(以较小者为准)。否则,如果您期望容器中有超过 CHAR_MAX
个元素,您将会遇到严重的溢出!
尝试使用reinterpret_cast。
示例:
#include <iostream>
#include <unistd.h>
#include <vector>
int main(int argc, char const *argv[])
{
std::vector<uint8_t> v{65,66,67,68,69,70};
char* ptr = reinterpret_cast<char*>(v.data());
for (auto i{0}; i < v.size(); i++) {
std::cout << *ptr++ << std::endl;
}
return 0;
}
您的情况:
void send(someId, reinterpret_cast<char*>(sco.data.data()), sco.data.size());
如果您至少可以使用 C++11,则 std::vector
class 提供 data()
其中 returns 原始数组。
如果您在 C++11 之前,恐怕您必须遍历向量并手动构建 char*
.
但是,你不能 static_cast
一个 unsigned char*
到一个 char*
。这是不允许的。
但你很幸运,char*
是一个例外,没有违反严格的别名规则。所以你可以使用 reinterpret_cast
代替。
所以您可以通过以下方式解决您的问题:
C++11 之前:
std::vector<uint8_t> a; // For the example
a.push_back('a');
a.push_back('b');
a.push_back('c');
a.push_back('d');
char b[a.size()];
for(unsigned int i = 0; i < a.size(); ++i)
{
b[i] = static_cast<char>(a[i]);
}
C++11之后:
std::vector<uint8_t> a {'a', 'b', 'c', 'd'}; //uint8_t aka unsigned char
char * b = reinterpret_cast<char*>(a.data()); // b is a char* so the reinterpret_cast is safe
希望对你有所帮助
我有一个 class 定义如下:
class sco
{
private:
public:
vector<uint8_t> data;
sco(vector<uint8_t> data);
~sco();
};
构造函数所在位置:
sco::sco(vector<uint8_t> data) {
this->data = data;
}
然后我有一个声明如下的函数:
void send(unsigned& id, char* data, char len);
我的问题是我需要将一个sco成员的数据传递给它,但是类型和指针的不同让我很困惑。如果我有一个成员 newSco,里面有一些数据,将这个发送函数称为 send(someId, (char*)&(newSco.data.begin()), newSco.data.size() );
是否合理?请注意,函数 send 是针对微控制器的,它接受 char 类型,所以我不能改变它,我也不能改变 uint8_t 因为这是来自串行通信的类型。我已经浪费了 3 天多的时间试图将类型转换为相互的东西,只是为了将其反转回来,因为它破坏了一切。我放弃了,我将不再尝试操纵类型,因为我只是没有那种时间,只是需要它工作,即使这是不好的做法。我以为 uint8_t 和 char 的大小相同,所以没关系。
是的,在这种情况下将指针转换为 char* 是合理的。通常,由于 strict aliasing rules,您可能不会使用不同类型的指针引用相同的内存位置。但是,'char' 是一种特殊情况,因此允许转换。
您不应该将 uint32_t* 转换为 int32_t,例如,即使它在某些情况下可能有效。
编辑:如以下评论所述:从 uint8_t* 转换为 char* 可能没问题,从迭代器转换则不然。使用 .data() 而不是 .begin()。
这应该有效:
send(someId, static_cast<char*>(&newSco.data[0]), static_cast<char>(newSco.data.size()));
附加信息:
How to convert vector to array
What is the difference between static_cast<> and C style casting?
send(someId, (char*)&(newSco.data.begin()), newSco.data.size() )
你几乎已经掌握了它,但还不够。
原因如下:
begin()
给你一个迭代器。您正在获取该迭代器的地址,因此您处于间接级别。使用 C-style 转换掩盖了 type-related 编译错误。我们可以写
(char*)&*(newSco.data.begin())
来取消引用迭代器,然后取第一个结果元素的地址。但是如果容器是空的,这就很破了。你不能取消引用一个不存在的东西。
所以现在我们尝试:
send(someId, (char*)&newSco.data[0], newSco.data.size() )
不幸的是,如果容器为空,也不安全,因为.data[0]
也有效地取消引用了一个可能不存在的元素。有人认为隐含的 &*
"cancels it out",但这是有争议的,我从不相信。
如果你曾经迁移到 C++11 或更高版本,你可以使用完全安全的:
send(someId, (char*)newSco.data.data(), newSco.data.size() )
否则,坚持使用 &newSco.data[0]
,但当 newSco.data.size()
为零 时跳过整个 send
调用。怎么强调都不为过。
转换为 char*
本身是安全的;您可以以这种方式自由地将 uint8_t
s 解释为 char
s;有一个特殊的规则。这个模式我自己用过几次。
但是,如上所述,C-style 演员表并不理想。喜欢一个很好的重新解释。我还会添加一些 const
以备不时之需(如果您的 MC API 不允许,请跳过此步骤):
if (!newSco.data.empty())
{
send(
someId,
reinterpret_cast<const char*>(&newSco.data[0]),
newSco.data.size()
);
}
那里。华丽的。
最后一点,由于 API 的最后一个参数是 char
,我会考虑为容器大小设置一个上限。您可以 运行 循环中的函数,一次发送 CHAR_MAX
或 newSco.data.size()
字节(以较小者为准)。否则,如果您期望容器中有超过 CHAR_MAX
个元素,您将会遇到严重的溢出!
尝试使用reinterpret_cast。 示例:
#include <iostream>
#include <unistd.h>
#include <vector>
int main(int argc, char const *argv[])
{
std::vector<uint8_t> v{65,66,67,68,69,70};
char* ptr = reinterpret_cast<char*>(v.data());
for (auto i{0}; i < v.size(); i++) {
std::cout << *ptr++ << std::endl;
}
return 0;
}
您的情况:
void send(someId, reinterpret_cast<char*>(sco.data.data()), sco.data.size());
如果您至少可以使用 C++11,则 std::vector
class 提供 data()
其中 returns 原始数组。
如果您在 C++11 之前,恐怕您必须遍历向量并手动构建 char*
.
但是,你不能 static_cast
一个 unsigned char*
到一个 char*
。这是不允许的。
但你很幸运,char*
是一个例外,没有违反严格的别名规则。所以你可以使用 reinterpret_cast
代替。
所以您可以通过以下方式解决您的问题:
C++11 之前:
std::vector<uint8_t> a; // For the example
a.push_back('a');
a.push_back('b');
a.push_back('c');
a.push_back('d');
char b[a.size()];
for(unsigned int i = 0; i < a.size(); ++i)
{
b[i] = static_cast<char>(a[i]);
}
C++11之后:
std::vector<uint8_t> a {'a', 'b', 'c', 'd'}; //uint8_t aka unsigned char
char * b = reinterpret_cast<char*>(a.data()); // b is a char* so the reinterpret_cast is safe
希望对你有所帮助