M.M*_*M.M 23 c strict-aliasing language-lawyer
代码1:
unsigned int *p = malloc(sizeof *p);
memset(p, 0x55, sizeof *p);
unsigned int u = *p;
Run Code Online (Sandbox Code Playgroud)
代码2:
void *d = malloc(50);
*(double *)d = 1.23;
memset(d, 0x55, 50);
unsigned int u = *(unsigned int *)d;
Run Code Online (Sandbox Code Playgroud)
在每种情况下,memset
对malloc空间中对象的有效类型有什么影响; 那么初始化u
正确还是严格的别名违规?
有效类型的定义(C11 6.5/6)是:
用于访问其存储值的对象的有效类型是对象的声明类型(如果有).如果通过具有非字符类型的左值的值将值存储到没有声明类型的对象中,则左值的类型将成为该访问的对象的有效类型以及不修改该值的后续访问的有效类型储值.如果使用
memcpy
或将值复制到没有声明类型的对象中memmove
,或者将其复制为字符类型数组,则该访问的修改对象的有效类型以及不修改该值的后续访问的有效类型是有效类型复制值的对象,如果有的话.对于没有声明类型的对象的所有其他访问,对象的有效类型只是用于访问的左值的类型.
然而,目前还不清楚是否memset
表现得像通过字符类型的左值或其他东西写作.memset
(7.24.6.1)的描述并不是很有启发性:
memset函数将c的值(转换为a
unsigned char
)复制到s指向的对象的前n个字符中.
我的50ct:
首先,我将其分解为句子以便于参考:
脚注可能在这里有所帮助:"87)分配的对象没有声明的类型." .
DNA:"不适用"
情况1:
memset(...)
:1:DNA(没有声明类型),2:DNA(memset写入char
- 语义),3:DNA(既不是memcpy也不是memmove),4:char []
仅用于内部memset(不是永久性的).unsigned int u = *p
:1:DNA(无声明类型),2/3:DNA(无写入,但读取),4:左值类型unsigned int
.结论:没有违规,但解释是实现定义的,因为实际值取决于变量和endianess内的对齐.
案例2:
*(double *)d = 1.23;
:2:d
成为double *
此和后续读取.memset(d, 0x55, 50);
:与案例1相同.unsigned int u = *(unsigned int *)d
:d
还是double *
:砰!无论如何,memset()
非char
标量用于非标量,除非使用0
仍然依赖于实现,否则(float)0.0
,空指针实际上不需要"所有位为零".
最后:
memset
内部,memset()
由char复制:"... c(转换为unsigned char)转换为前n个字符中的每一个......"(或char
至少使用语义;实际实现是这里无关紧要).memset()
,因为它仅适用于memcpy
/ memmove
或当复制为"字符类型数组"时.它也没有(但前者是这样的,所以or
-condition只是使一个显式的复制循环等效于函数).memset()
并没有改变它的有效类型的对象.这与memcpy
和不同memmove
.这是由句子4产生的,它不包括"......对于那个访问和随后的访问......",因为2和3状态和1暗示.希望有所帮助.建设性的批评欢迎.