将二进制字节(char *)转换为uint64_t *,是否安全?

时间:2018-01-02 07:09:13

标签: c++ casting memory-alignment

我正在编写这个从远程服务器接收包的C ++代码。由于包的大小事先是未知的,因此代码首先接收8个字节,它告诉整个包的大小。然后它分配一个足够大的缓冲区并将整个包接收到缓冲区中。

我的问题是从const char*转换为uint64_t*部分:是否可以安全地转换指针,然后将内容读作uint64_t?如果buf未与8个字节对齐怎么办?

const char* buf;
RecvBytes(buf, sizeof(uint64_t));    // the first 8 bytes should tell us the size of the whole package
uint64_t pkg_size = *(uint64_t*)buf;  // is this safe??
const char* pkg = new char[pkg_size];
RecvBytes(pkg, pkg_size);

4 个答案:

答案 0 :(得分:2)

嗯,一般情况下,这应该没问题,但在一种情况下,可能有效,具体取决于发件人传递的实际参数的类型。

换句话说,如果发件人正在发送指向uint64_t类型的指针,只有在这种情况下,代码才可以接受。

引用C11,章节§6.3.2.3

  

指向对象类型的指针可以转换为指向不同对象类型的指针。如果   结果指针未正确对齐68)对于引用的类型,行为是   未定义。否则,当再次转换回来时,结果应该等于   原始指针。

答案 1 :(得分:0)

一般情况下,只有将(pauseOnDotsHover: false, respondTo: 'window', responsive: null, rtl: true, slide: '', slidesToShow: 1, slidesToScroll: 1, speed: 500, const强制转换为类型才是安全的,如果指针是从该类型获取然后再转换为char *

所以这里的防弹方式是:

char *

答案 2 :(得分:0)

  

我正在编写这个从远程服务器接收包的C ++代码。由于包的大小事先是未知的,因此代码首先接收8个字节,它告诉整个包的大小。然后它分配一个足够大的缓冲区并将整个包接收到缓冲区中。

我认为在包交换的上下文中,你不应该动态地分配一些东西,或者至少不是没有最大大小。 (并在必要时循环计算所有数据)

我会在你的情况下做这样的事情:

union {
  uint64_t size;
  char bytes[sizeof size];
} tmp;
RecvBytes(tmp.bytes, sizeof tmp.bytes);
if (tmp.size > SIZE_MAX) {
  // bad
}
size_t size = static_cast<size_t>(tmp.size); // or use tmp.size

char data[MAX]; // or use something more object
for (size_t i = 0; i < size; i += MAX) {
  RecvBytes(data, min(size - i, MAX));
  // compute data
}

答案 3 :(得分:0)

  

我的问题是从const char *到uint64_t * part的转换:是否可以安全地转换指针,然后将内容读取为uint64_t?

一般情况下,它不安全且为undefined behavior,因此您应该scared。例如,您的代码可能会在PowerPC计算机上崩溃,其中指向uint64_t的指针应与8个字节对齐(否则,在解除引用时,可能会出现SIGBUSSIGSEGV错位指针)。

  

如果buf没有与8个字节对齐怎么办?

x86处理器上,您可以使用它们:允许取消引用未对齐的指针,但是效率低(因此您应该避免这样做)。

动态分配的指针(由malloc::operator new获得)保证足够对齐,因此new char[x]的结果可以安全地转换为uint64_t*