根据Effective C ++,“将对象地址转换为char *指针然后在它们上使用指针arithemetic几乎总是会产生未定义的行为。”
对于普通旧数据,这是真的吗?例如,在我很久以前写的这个模板函数中打印一个对象的位。它在x86上运行得非常好,但是......它是否可移植?
#include <iostream>
template< typename TYPE >
void PrintBits( TYPE data ) {
unsigned char *c = reinterpret_cast<unsigned char *>(&data);
std::size_t i = sizeof(data);
std::size_t b;
while ( i>0 ) {
i--;
b=8;
while ( b > 0 ) {
b--;
std::cout << ( ( c[i] & (1<<b) ) ? '1' : '0' );
}
}
std::cout << "\n";
}
int main ( void ) {
unsigned int f = 0xf0f0f0f0;
PrintBits<unsigned int>( f );
return 0;
}
答案 0 :(得分:2)
是的,POD类型始终可以视为大小为sizeof (TYPE)
的字符数组。 POD类型就像对应的C类型(这就是它们“普通,旧”的原因)。由于C没有函数重载,因此编写“通用”函数来执行将它们写入文件或网络流的操作取决于将它们作为char数组进行访问的能力。
答案 1 :(得分:2)
当然不便携。即使您坚持使用基本类型,也有endianness并且有sizeof,因此您的函数将在big-endian机器上或在sizeof(int)为16或64的机器上打印不同的结果。另一个问题是并非所有POD都是基本类型,结构也可能是POD。
POD结构成员可以根据实现定义的对齐规则具有内部填充。所以如果你传递这个POD结构:
struct PaddedPOD
{
char c;
int i;
}
您的代码也会打印填充内容。即使在具有不同编译指示和选项的相同编译器上,该填充也会有所不同。
另一方面,也许这就是你想要的。
所以,它不是便携式的,但它不是UB。有一些标准保证:您可以将POD复制到char或unsigned char数组中,并且通过char缓冲区复制的结果将保留原始值。这意味着您可以安全地遍历该数组,因此您的功能是安全的。但是没有人保证这个具有相同类型和值的对象的数组(或对象表示)在不同的计算机上是相同的。
BTW,我在Effective C ++中找不到这段话。你能引用它,请问?我可以说,如果你的代码的一部分已经包含了很多#ifdef thiscompilerversion
,有时候使用非标准并使用一些导致未定义行为的hack是有意义的,但是在这个编译器版本中使用此pragma工作和选项。从这个意义上讲,是的,施展到char *通常会导致UB。