在动态bool数组上使用memset是否定义明确?

在严格别名方面,这段代码是明确定义的行为吗?

_Bool* array = malloc(n); memset(array, 0xFF, n); _Bool x = array[0]; 

有效类型的规则有memcpymemmove特殊情况(C176.5§6),但不适用于memset

我的看法是有效类型变为unsigned char 。 因为memset的第二个参数需要转换为unsigned char (C17 7.24.6.1),并且由于有效类型的规则,(C176.5§6):

…或者被复制为字符类型数组,然后该访问的修改对象的有效类型以及不修改该值的后续访问是从中复制值的对象的有效类型,如果它有一个。

  • 问题1:在memset调用之后, array存储的数据的有效类型是什么?
  • 问题2: array[0]访问是否违反了严格的别名? 由于_Bool不是严格别名规则中排除的类型(与字符类型不同)。

  1. memset不会更改有效类型。 C11(C17)6.5p6:

    1. 用于访问其存储值的对象的有效类型是对象的声明类型(如果有)。 [事实显然并非如此。 已分配的对象没有声明的类型。 ]

      如果通过具有非字符类型的类型的左值将值存储到没有声明类型的对象中,则左值的类型将成为该访问的对象的有效类型以及不修改该值的后续访问的有效类型储值。 [不是这种情况,因为memset使用了字符类型的左值! ]

      如果使用memcpymemmove将值复制到没有声明类型的对象中,或者将其复制为字符类型数组 ,则该访问的修改对象的有效类型以及不修改该值的后续访问的有效类型是复制值的对象的有效类型(如果有)。 [这里也不是这种情况 – 它不会与memcpymemmove或字符数组一起复制]

      对于没有声明类型的对象的所有其他访问,对象的有效类型只是用于访问的左值的类型。 [因此,这必须适用于我们的情况。 请注意,这适用于将其作为memset内的字符以及解除引用array进行访问。 ]

    由于这些值一个在memset中具有字符类型的lvalue值存储,并且没有具有字符类型的lvalue 另一个对象复制的字节 (该子句用于将memcpymemmove等同于使用显式for循环执行相同的操作!),它没有得到有效的类型, 对于那些通过array访问的元素,有效的元素类型是_Bool

    C17标准中可能有一些部分未被指定,但这肯定不是其中之一。

  2. array[0]不会违反有效类型规则。

    这不会使使用array[0]的值更合法。 它可以(并且很可能)是一个陷阱值!

    我尝试了以下function

     #include  #include  void f1(bool x, bool y) { if (!x && !y) { puts("both false"); } } void f2(bool x, bool y) { if (x && y) { puts("both true"); } } void f3(bool x) { if (x) { puts("true"); } } void f4(bool x) { if (!x) { puts("false"); } } 

    使用array[0]作为任何参数 – 为了避免编译时优化,这是单独编译的。 使用-O3编译时,打印了以下消息:

     both true true 

    而没有任何优化

     both false both true true false