将对象地址强制转换为char ptr,然后对其使用指针数学 根据有效的C++,将对象映射到char指针,然后使用指针对它们几乎总是产生未定义的行为。

将对象地址强制转换为char ptr,然后对其使用指针数学 根据有效的C++,将对象映射到char指针,然后使用指针对它们几乎总是产生未定义的行为。,c++,pointers,portability,C++,Pointers,Portability,对于普通的旧数据,这是真的吗?例如,在我很久以前编写的这个模板函数中,打印对象的位。它在x86上工作得非常出色,但是。。。它是便携式的吗 #include <iostream> template< typename TYPE > void PrintBits( TYPE data ) { unsigned char *c = reinterpret_cast<unsigned char *>(&data); std::size_t

对于普通的旧数据,这是真的吗?例如,在我很久以前编写的这个模板函数中,打印对象的位。它在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;
}

是的,POD类型始终可以被视为一个字符数组,大小为sizeof TYPE。POD类型和对应的C类型一样,这使它们简单、古老。由于C没有函数重载,所以编写通用函数来执行诸如将它们写入文件或网络流之类的操作取决于是否能够将它们作为字符数组进行访问。

是的,POD类型始终可以被视为大小为sizeof TYPE的字符数组。POD类型和对应的C类型一样,这使它们简单、古老。由于C没有函数重载,因此编写通用函数来执行诸如将它们写入文件或网络流之类的操作取决于能否将它们作为字符数组进行访问。

它当然不可移植。即使您坚持使用基本类型,也存在endianness和sizeof,因此您的函数将在big-endian机器或sizeofint为16或64的机器上打印不同的结果。另一个问题是并非所有的POD都是基本类型,结构也可能是POD

根据实现定义的对齐规则,POD结构成员可以具有内部填充。因此,如果您通过此POD结构:

struct PaddedPOD
{
char c;
int i;
}
您的代码也会打印填充的内容。即使在同一个编译器上使用不同的pragma和选项,填充也会不同

另一方面,也许这正是你想要的

所以,它不是便携式的,但它不是UB。有一些标准的保证:您可以在char或unsigned char数组之间复制pod,通过char buffer复制的结果将保留原始值。这意味着您可以安全地遍历该数组,因此您的函数是安全的。但是,没有人能保证相同类型和值的对象的数组或对象表示在不同的计算机上是相同的


在有效C++中,我找不到这一段。请给我报价好吗?我可以说,如果您的代码的一部分已经包含了大量的ifdef thiscompilerversion,那么有时使用一些导致未定义行为的非标准方法是有意义的,但是使用这个pragmas和选项可以在这个编译器版本上按预期工作。从这个意义上说,是的,对char*进行强制转换通常会导致UB。

它当然是不可移植的。即使您坚持使用基本类型,也存在endianness和sizeof,因此您的函数将在big-endian机器或sizeofint为16或64的机器上打印不同的结果。另一个问题是并非所有的POD都是基本类型,结构也可能是POD

根据实现定义的对齐规则,POD结构成员可以具有内部填充。因此,如果您通过此POD结构:

struct PaddedPOD
{
char c;
int i;
}
您的代码也会打印填充的内容。即使在同一个编译器上使用不同的pragma和选项,填充也会不同

另一方面,也许这正是你想要的

所以,它不是便携式的,但它不是UB。有一些标准的保证:您可以在char或unsigned char数组之间复制pod,通过char buffer复制的结果将保留原始值。这意味着您可以安全地遍历该数组,因此您的函数是安全的。但是,没有人能保证相同类型和值的对象的数组或对象表示在不同的计算机上是相同的


在有效C++中,我找不到这一段。请给我报价好吗?我可以说,如果您的代码的一部分已经包含了大量的ifdef thiscompilerversion,那么有时使用一些导致未定义行为的非标准方法是有意义的,但是使用这个pragmas和选项可以在这个编译器版本上按预期工作。从这个意义上说,是的,强制转换到char*通常会导致UB。

我没有花时间在这里完全摸索代码,但我知道可能导致未定义行为或崩溃的一个原因是,如果您尝试使用指针算法将随机地址视为int,它不一定与字边界0、4、8、12、16等字节对齐。好的,现在我确实理解了代码,正如我所怀疑的那样,这不会是一个问题,因为您永远不会回溯到int。我不知道这样做是否还有其他问题。我没有花时间在这里仔细研究代码,但我知道可能导致未定义行为或崩溃的一个原因是,如果您尝试使用指针算法将随机地址视为int,它不一定与字边界0、4、8、12、16等字节对齐。好的,现在我确实理解了代码,正如我所怀疑的,这不会是一个问题
因为你再也不能回到int了。我不知道是否还有其他问题。这一段可以在有效的C++第三版中找到,在第27项下的第119页,尽量减少页面顶部的外壳。在有效的C++第三版本中,可以在第27条下找到第119页,尽量减少页面顶部的外壳。