在数组末尾刚好在指针上调用零长度的memcpy是否合法? [英] Is it legal to call memcpy with zero length on a pointer just past the end of an array?

查看:421
本文介绍了在数组末尾刚好在指针上调用零长度的memcpy是否合法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在其他地方回答,使用无效或NULL指针调用memcpy之类的函数是不确定的行为,即使length参数为零.在这样的函数的上下文中,尤其是memcpymemmove,刚好位于数组末尾的指针是有效的指针吗?

As answered elsewhere, calling functions like memcpy with invalid or NULL pointers is undefined behaviour, even if the length argument is zero. In the context of such a function, especially memcpy and memmove, is a pointer just past the end of the array a valid pointer?

我问这个问题是因为获取一个指向数组末尾的指针是合法的(与之相反,例如,指向指向数组末尾两个元素的指针),但是您仍然不能取消引用它ISO 9899:2011的脚注106指示此类指针指向程序的地址空间,根据§7.1.4,指针有效的标准.

I'm asking this question because a pointer just past the end of an array is legal to obtain (as opposed to, e.g. a pointer two elements past the end of an array) but you are not allowed to dereference it, yet footnote 106 of ISO 9899:2011 indicates that such a pointer points to into the address space of the program, a criterion required for a pointer to be valid according to §7.1.4.

这种用法发生在代码中,我想将一个项目插入到数组的中间,要求我将所有项目移动到插入点之后:

Such usage occurs in code where I want to insert an item into the middle of an array, requiring me to move all items after the insertion point:

void make_space(type *array, size_t old_length, size_t index)
{
    memmove(array + index + 1, array + index, (old_length - index) * sizeof *array);
}

如果要插入数组的末尾,则index等于length,并且array + index + 1指向数组的末尾,但是复制的元素数为零.

If we want to insert at the end of the array, index is equal to length and array + index + 1 points just past the end of the array, but the number of copied elements is zero.

推荐答案

3.15对象

3.15 object

  1. 对象 执行环境中数据存储的区域,其内容可以表示 值
  1. object region of data storage in the execution environment, the contents of which can represent values

指向数组对象或对象的最后一个元素所指向的内存的指针不能表示值,因为它不能被取消引用(6.5.6加法运算符,第8段).

The memory, pointer to one past the last element points to, of an array object or an object cannot represent values, since it cannot be dereferenced ( 6.5.6 Additive operators, paragraph 8 ).

7.24.2.1 memcpy函数

7.24.2.1 The memcpy function

  1. memcpy函数将s2指向的 object 中的n个字符复制到 s1指向的 object .如果复制发生在重叠的对象之间,则行为 未定义.
  1. The memcpy function copies n characters from the object pointed to by s2 into the object pointed to by s1. If copying takes place between objects that overlap, the behavior is undefined.

传递给memcpy的指针必须指向一个对象.

Pointers passed to memcpy must point to an object.

6.5.3.4 sizeof和_Alignof运算符

6.5.3.4 The sizeof and _Alignof operators

  1. 将sizeof应用于类型为char,unsigned char或 签名字符(或限定版本)为1.当应用于 具有数组类型的操作数,结果是数组中的字节总数.什么时候 应用于具有结构或并集类型的操作数,结果是此类对象中的字节总数 ,包括内部填充和结尾填充.
  1. When sizeof is applied to an operand that has type char, unsigned char, or signed char, (or a qualified version thereof) the result is 1. When applied to an operand that has array type, the result is the total number of bytes in the array. When applied to an operand that has structure or union type, the result is the total number of bytes in such an object, including internal and trailing padding.

sizeof运算符不将单行元素视为对象,因为它不计入对象的大小.显然,它给出了整个对象的大小.

sizeof operator doesn't count the one-past element as the object, since it doesn't count towards the size of the object. Yet it clearly gives the size of the entire object.

6.3.2.1左值,数组和函数指示符

6.3.2.1 Lvalues, arrays, and function designators

  1. 左值是一个表达式(对象类型不是void),它可能 指定一个对象; 64)如果左值在求值时未指定对象,则 行为是不确定的.
  1. An lvalue is an expression (with an object type other than void) that potentially designates an object; 64) if an lvalue does not designate an object when it is evaluated, the behavior is undefined.

我认为指向数组对象或对象的一个​​过去的指针不能表示一个对象.

I argue that the one past pointer to an array object or an object, both of which are otherwise allowed to point to, does not represent an object.

int a ;
int* p = a+1 ; 

p已定义,但是它不指向对象,因为它不能被取消引用,它指向的内存不能表示一个值,并且sizeof不会将该内存计为对象的一部分. Memcpy需要一个指向对象的指针.

p is defined, but it does not point to an object since it cannot be dereferenced, the memory it points to cannot represent a value, and sizeof doesn't count that memory as a part of the object. Memcpy requires a pointer to an object.

因此,将过去的指针传递给memcpy会导致未定义的行为.

Therefore the passing one past pointer to memcpy causes undefined behavior.

更新:

这部分还支持以下结论:

This part also support the conclusion:

6.5.9相等运算符

6.5.9 Equality operators

  1. 当且仅当两个都是空指针,并且两个都是指向的指针时,两个指针的比较结果相等. 相同的对象(包括指向对象的指针和在其开头的子对象)或函数, 两者都是指向同一数组对象最后一个元素之后的指针,或者是一个指针 指向一个数组对象的末尾,另一个是指向另一个数组的开始的指针 恰好紧跟在地址中第一个数组对象之后的数组对象 空间.
  1. Two pointers compare equal if and only if both are null pointers, both are pointers to the same object (including a pointer to an object and a subobject at its beginning) or function, both are pointers to one past the last element of the same array object, or one is a pointer to one past the end of one array object and the other is a pointer to the start of a different array object that happens to immediately follow the first array object in the address space.

这意味着指向一个对象的指针如果增加到一个对象之后,则可以指向另一个对象.在那种情况下,它肯定不能指向它最初指向的对象,表明指针越过一个对象并不指向一个对象.

This implies that pointer to an object if incremented to one past an object, can point to a different object. In that case, it certainly cannot point to the object it pointed to originally, showing that pointer one past an object doesn't point to an object.

这篇关于在数组末尾刚好在指针上调用零长度的memcpy是否合法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆