就严格的别名而言,此代码的行为是否定义明确?
_Bool* array = malloc(n);
memset(array, 0xFF, n);
_Bool x = array[0];
有效类型的规则在memcpy
和memmove
中有特殊情况(C17 6.5§6),在memset
中则没有。
我认为有效类型变为unsigned char
。因为memset
的第二个参数需要转换为unsigned char
(C17 7.24.6.1),并且由于有效类型的规则,所以(C17 6.5§6):
...或被复制为字符类型的数组,然后是有效类型 修改后的对象的访问权限以及不修改 值是从中复制值的对象的有效类型(如果有)。
array
调用之后,存储在memset
中的数据的有效类型是什么?array[0]
访问是否因此违反严格的别名?由于_Bool
不是严格的别名规则所排除的类型(与字符类型不同)。答案 0 :(得分:7)
memset
不会不更改有效类型。 C11 (C17) 6.5p6:
用于访问其存储值的对象的有效类型为 对象的声明类型(如果有)。 [显然不是这样。分配的对象没有声明的类型。 ]
如果将值存储到 通过具有以下类型的左值而没有声明类型的对象 是不是字符类型,则左值的类型变为 该访问以及后续访问的对象的有效类型 不会修改存储值的访问。 [情况并非如此,因为
memset
使用字符类型的左值! ]如果已复制一个值 使用
memcpy
或memmove
或进入没有声明类型的对象 复制为字符类型数组,然后输入有效类型 修改的对象,用于该访问以及随后的访问 不修改值是从哪个有效对象类型 值被复制(如果有)。 [这里也不是这种情况-不会使用memcpy
,memmove
或字符数组来复制]用于对其他所有 没有声明类型的对象,则该对象的有效类型为 只是用于访问的左值的类型。 [因此,这在我们的情况下必须适用。请注意,这适用于在
memset
中作为字符进行访问以及取消对array
的引用。 ]
由于值存储在lvalue
中且字符类型为memset
的{{1}}中,并且没有从另一个具有字符类型左值的对象复制的字节(该子句的存在是将memcpy
和memmove
等同于通过显式的for
循环执行!),它没有得到有效的类型,而没有有效的类型对于通过_Bool
访问的元素,元素是array
。
C17标准中的某些部分可能未得到充分说明,但这当然不是其中一种。
array[0]
不会违反有效类型规则。
使用array[0]
的值不再合法。它可以(而且很可能是)陷阱值!
我尝试了以下功能
#include <stdio.h>
#include <stdbool.h>
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