memset编写的对象的有效类型是什么?
代码1:
unsigned int *p = malloc(sizeof *p); memset(p, 0x55, sizeof *p); unsigned int u = *p;
代码2:
void *d = malloc(50); *(double *)d = 1.23; memset(d, 0x55, 50); unsigned int u = *(unsigned int *)d;
在每种情况下, memset
对malloc空间中对象的有效类型有什么影响; 那么初始化u
正确的还是严格的别名违规?
有效类型的定义(C11 6.5 / 6)是:
用于访问其存储值的对象的有效类型是对象的声明类型(如果有)。 如果通过具有非字符类型的类型的左值将值存储到没有声明类型的对象中,则左值的类型将成为该访问的对象的有效类型以及不修改该值的后续访问的有效类型储值。 如果使用
memcpy
或memmove
将值复制到没有声明类型的对象中,或者将其复制为字符类型数组,则该访问的修改对象的有效类型以及不修改该值的后续访问的有效类型是复制值的对象的有效类型(如果有)。 对于没有声明类型的对象的所有其他访问,对象的有效类型只是用于访问的左值的类型。
然而,目前还不清楚memset
行为是否像通过字符类型的左值或其他东西写作一样。 memset
(7.24.6.1)的描述并不是很有启发性:
memset函数将c的值(转换为
unsigned char
)复制到s指向的对象的前n个字符中。
我的50ct:
首先,我将其分解为句子以便于参考:
- 用于访问其存储值的对象的有效类型是对象的声明类型(如果有)。
- 如果通过具有非字符类型的类型的左值将值存储到没有声明类型的对象中,则左值的类型将成为该访问的对象的有效类型以及不修改该值的后续访问的有效类型储值。
- 如果使用memcpy或memmove将值复制到没有声明类型的对象中,或者将其复制为字符类型数组,则该访问的修改对象的有效类型以及不修改该值的后续访问的有效类型是复制值的对象的有效类型(如果有)。
- 对于没有声明类型的对象的所有其他访问,对象的有效类型只是用于访问的左值的类型。
脚注可能在这里有所帮助: “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 *
:bang!
无论如何, memset()
对于非char
标量是非常有用的,除非使用0
,它仍然是依赖于实现的 ,因为(float)0.0
和空指针都不需要实际上是“所有位为零”。
最后:
- 句子2不适用于
memset
,因为在内部,memset()
通过char复制:“…将c(转换为unsigned char)转换为前n个字符中的每一个……”(或者使用char
语义,至少;实际执行与此无关)。 - 句子3也不适用于
memset()
,因为它仅适用于memcpy
/memmove
或复制为“字符类型数组”。 它也没有(但前者是这样,所以or
-condition只是使一个显式的复制循环等效于函数)。 -
memset()
不会更改对象的有效类型 。 这与memcpy
和memmove
不同。 这是由句子4产生的,句子4不包括“……对于那个访问和随后的访问……”,因为2和3状态和1暗示。
希望有所帮助。 建设性的批评欢迎。