我正在实施一个版本memcpy()
能够与它一起使用volatile
。
使用安全吗char *
或者我需要unsigned char *
?
volatile void *memcpy_v(volatile void *dest, const volatile void *src, size_t n)
{
const volatile char *src_c = (const volatile char *)src;
volatile char *dest_c = (volatile char *)dest;
for (size_t i = 0; i < n; i++) {
dest_c[i] = src_c[i];
}
return dest;
}
I think unsigned
如果缓冲区的任何单元中的数据是,应该有必要避免溢出问题> INT8_MAX
,我认为可能是UB。
理论上,您的代码可能会在一台禁止签名中使用一位模式的机器上运行。char
。它可能使用负整数的补码或符号数值表示,其中一位模式将被解释为带负号的 0。即使在补码架构上,该标准也允许实现限制负整数的范围,以便INT_MIN == -INT_MAX
,尽管我不知道有任何实际机器可以做到这一点。
因此,根据 §6.2.6.2p2,可能存在一个有符号字符值,实现可能会将其视为陷阱表示:
应用这些 [负整数的表示] 中的哪一个是实现定义的,就像是符号位为 1 且所有值位为零的值(对于前两个 [符号量值和二进制补码]),还是符号位和所有值都为零值位 1(用于补码)是陷阱表示或正常值。在符号和大小以及补码的情况下,如果这种表示是正常值,则称为负零.
(字符类型不能有任何其他陷阱值,因为第 6.2.6.2 节要求signed char
没有任何填充位,这是形成陷阱表示的唯一其他方式。出于同样的原因,没有位模式是陷阱表示unsigned char
.)
所以,如果这个假设的机器有一个 C 实现,其中char
是有符号的,那么有可能通过a复制任意字节char
将涉及复制陷阱表示。
对于有符号整数类型以外的char
(如果碰巧签署)和signed char
,读取陷阱表示的值是未定义的行为。但§6.2.6.1/5允许读取和写入这些值仅适用于字符类型:
某些对象表示不需要表示对象类型的值。如果对象的存储值具有这样的表示形式并且由左值表达式读取没有字符类型,行为未定义。如果这样的表示是由副作用产生的,即通过不具有字符类型的左值表达式修改对象的全部或任何部分,则行为是未定义的。这种表示称为陷阱表示。(强调已添加)
(第三句话有点笨拙,但为了简化:将值存储到内存中是“修改所有对象的副作用”,因此也是允许的。)
简而言之,由于该例外,您可以使用char
在实施中memcpy
不用担心未定义的行为。
然而,情况并非如此strcpy
. strcpy
必须检查终止字符串的尾部 NUL 字节,这意味着它需要将从内存中读取的值与 0 进行比较。并且比较运算符(实际上,所有算术运算符)首先对其操作数执行整数提升,这会将char
to an int
。据我所知,陷阱表示的整数提升是未定义的行为,因此在假设机器上运行的假设 C 实现上,您需要使用unsigned char
为了实施strcpy
.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)