将unsigned char数组解释为bool数组

时间:2014-08-14 13:05:09

标签: c++ gcc casting boolean

请考虑以下代码。它没问题还是会导致未定义的行为?

#include <iostream>

int main()
{
    {
        unsigned char binary[] = {0, 5, 10};
        bool* x = reinterpret_cast<bool*>(&binary[0]);

        for (unsigned int i = 0; i < 3; ++i)
        {
            std::cout << (x[i] ? 1 : 0) << " ";
        }
    }

    {
        unsigned char b = 255;
        bool* x = reinterpret_cast<bool*>(&b);
        std::cout << (*x ? 1 : 0) << std::endl;
    }

    return 0;
}

使用gcc 4.6到4.8编译时的输出是

0 5 10 1

但仅限于优化(-O1及更多)。 Clang结果

0 1 1 1

即使有优化。 现在,如果将y[i] ? 1 : 0更改为y[i] ? 2 : 1 gcc结果

1 2 2 1

任何想法或者因为演员而只是未定义的行为?

2 个答案:

答案 0 :(得分:6)

该标准并不保证boolchar完全兼容(即不保证它们具有相同的大小或对齐方式),并说:

  

bool类型的值为truefalse

     

§3.9.1[basic.fundamental]

它还说:

  

将本国际标准所描述的方式中的bool值用作“未定义”,例如通过检查未初始化的自动对象的值,可能会使其表现得好像既不是true也不是false

     

脚注47(N3337)

因此,您处于未定义行为的范畴。

请注意,由于标准不会使bool成为例外,因此适用以下规则:

  

如果程序试图通过以下类型之一以外的glvalue访问对象的存储值,则行为未定义:

     

- 对象的动态类型,

     

- 对象的动态类型的cv限定版本,

     

- 与对象的动态类型相似的类型(如4.4中所定义)

     

- 与对象的动态类型对应的有符号或无符号类型

     

- 对应于对象动态类型的cv限定版本的有符号或无符号类型,

     

- 聚合或联合类型,包括其元素或非静态数据成员中的上述类型之一(包括递归地,子聚合或包含联合的元素或非静态数据成员),

     

- 一种类型,是对象动态类型的(可能是cv限定的)基类类型,

     

- char或unsigned char类型。

     

§3.10[basic.lval]

在这种情况下,对象的类型是unsigned char,因此尝试通过bool左值(通过解除引用bool *获得的那个)访问它们会导致UB。

答案 1 :(得分:2)

这违反strict aliasing rule,我会引用我的回答here

  

严格的别名规则,这使得访问对象成为非法   通过一个不同类型的指针,虽然通过char访问   * 被允许。允许编译器假设不同类型的指针不指向相同的内存并进行优化   因此。它还意味着代码调用未定义的行为和   真的可以做任何事情。

标准草案在3.10 Lvalues和rvalues 段落 10 中涵盖了这一点:

  

如果程序试图通过访问对象的存储值   行为是除以下类型之一以外的glvalue   未定义: 52

     

- 对象的动态类型,

     

- 对象的动态类型的cv限定版本,

     

- 与对象的动态类型相似的类型(如4.4中所定义)

     

- 与对象的动态类型对应的有符号或无符号类型

     

- 对应于动态类型的cv限定版本的有符号或无符号类型   对象,

     

- 聚合或联合类型,包括其元素中的上述类型之一或非静态类型   数据成员(包括,递归地,子集合的元素或非静态数据成员   或包含联盟),

     

- 一种类型,是对象动态类型的(可能是cv限定的)基类类型,

     

- char或unsigned char类型。

如果这不是问题,则不清楚,尝试将bool解释为char甚至是有效的,3.9.1 基本类型部分说:

  

bool类型的值为true或false。[...]

脚注 47 表示:

  

以本国际标准描述的方式将bool值用作“未定义”,例如通过检查a的值   未初始化的自动对象,可能会使其表现为既不是真也不是假。