Ter*_*sao 3 c++ reinterpret-cast pointer-conversion
这困扰了我很长时间:如何进行从任何东西char *到将二进制文件转储到磁盘的指针转换。
在C语言中,您甚至无需考虑。
double d = 3.14;
char *cp = (char *)&d;
// do what u would do to dump to disk
Run Code Online (Sandbox Code Playgroud)
但是,在C ++中,每个人都说C-cast不被接受,我一直在这样做:
double d = 3.14;
auto cp = reinterpret_cast<char *>(&d);
Run Code Online (Sandbox Code Playgroud)
现在这是从cppreference复制的,所以我认为这是正确的方法。
但是,我从多个消息来源读到这是UB。(例如,这个)所以我不禁要问是否有任何“ DB”方式(根据那篇文章,没有)。
我经常遇到的另一种情况是实现这样的API:
void serialize(void *buffer);
Run Code Online (Sandbox Code Playgroud)
您将在其中将很多东西转储到此缓冲区。现在,我一直在这样做:
void serialize(void *buffer) {
int intToDump;
float floatToDump;
int *ip = reinterpret_cast<int *>(buffer);
ip[0] = intToDump;
float *fp = reinterpret_cast<float *>(&ip[1]);
fp[0] = floatToDump;
}
Run Code Online (Sandbox Code Playgroud)
好吧,我想这也是UB。
现在,真的没有“ DB”方法可以完成这两项任务吗?我见过有人uintptr_t用来完成类似于sth的serialize任务,将指针与一起作为整数数学sizeof,但我猜这里也是UB。
即使他们是UB,编译器作者也通常会做一些合理的事情来确保一切正常。我对此表示同意:要求这不是不合理的事情。
因此,对于上述两个常见任务,我的问题确实是:
谢谢!
您的serialize实现行为是不确定的,因为您违反了严格的别名规则。简而言之,严格的别名规则表明,您不能通过指针或其他类型的引用来引用任何对象。有一个主要例外该规则虽然:任何对象可经由指针被引用到char,unsigned char或(因为C ++ 17) std::byte。请注意,此异常不适用于其他情况;一个char阵列可以不经由指针以外的类型来访问char。
这意味着您可以serialize通过如下更改使其功能良好定义:
void serialize(char* buffer) {
int intToDump = 42;
float floatToDump = 3.14;
std::memcpy(buffer, &intToDump, sizeof(intToDump));
std::memcpy(buffer + sizeof(intToDump), &floatToDump, sizeof(floatToDump));
// Or you could do byte-by-byte manual copy loops
// i.e.
//for (std::size_t i = 0; i < sizeof(intToDump); ++i, ++buffer) {
// *buffer = reinterpret_cast<char*>(&intToDump)[i];
//}
//for (std::size_t i = 0; i < sizeof(floatToDump); ++i, ++buffer) {
// *buffer = reinterpret_cast<char*>(&floatToDump)[i];
//}
}
Run Code Online (Sandbox Code Playgroud)
在这里,不是强制转换buffer为不兼容类型的指针,而是std::memcpy强制转换为对象的指针以序列化为的指针unsigned char。这样,就不会违反严格的别名规则,并且程序的行为仍保持良好定义。请注意,确切的表示形式仍未指定;因为这将取决于您的CPU的耐久性。
| 归档时间: |
|
| 查看次数: |
130 次 |
| 最近记录: |