在刚过数组末尾的指针上调用长度为零的memcpy合法吗?

在刚过数组末尾的指针上调用长度为零的memcpy合法吗?,c,pointers,language-lawyer,undefined-behavior,C,Pointers,Language Lawyer,Undefined Behavior,同样,使用无效或NULL指针调用memcpy等函数是未定义的行为,即使length参数为零。在这种函数的上下文中,尤其是memcpy和memmove,刚刚超过数组末尾的指针是有效指针吗 我问这个问题是因为刚过数组末尾的指针是合法获取的(与之相反,例如,一个指针超过数组末尾的两个元素),但不允许取消引用它,然而ISO 9899:2011的脚注106指出,这样的指针指向程序的地址空间,根据§7.1.4,指针有效所需的标准 这种用法出现在我想将一个项插入数组中间的代码中,要求我在插入点之后移动所有项:

同样,使用无效或
NULL
指针调用
memcpy
等函数是未定义的行为,即使length参数为零。在这种函数的上下文中,尤其是
memcpy
memmove
,刚刚超过数组末尾的指针是有效指针吗

我问这个问题是因为刚过数组末尾的指针是合法获取的(与之相反,例如,一个指针超过数组末尾的两个元素),但不允许取消引用它,然而ISO 9899:2011的脚注106指出,这样的指针指向程序的地址空间,根据§7.1.4,指针有效所需的标准

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

void make_space(type *array, size_t old_length, size_t index)
{
    memmove(array + index + 1, array + index, (old_length - index) * sizeof *array);
}
如果要在数组末尾插入,
索引
等于
长度
数组+索引+1
点刚好超过数组末尾,但复制的元素数为零。

如果查看

7.21.1.p2

其中声明为size\u t n的参数指定 数组中,n可以在调用该函数时具有值零 功能。除非说明书中另有明确规定 此子类中的特定函数,指针参数 调用仍应具有有效值,如7.1.4所述。就这样 调用时,查找字符的函数不会找到任何匹配项 比较两个字符序列的函数返回零,而 复制字符的函数复制零个字符。

7.21.2.1

7.1.4.p1

。。。如果函数参数被描述为数组,则指针 实际传递给函数的值应为all 处理计算和对象访问(如果 指针确实指向这样一个数组的第一个元素)中 事实有效

重点补充。似乎指针必须指向有效的位置(在去引用的意义上),而关于指针算术允许指向末尾+1的段落在这里不适用

问题在于
memcpy
的参数是否为数组。当然,它们不是声明为数组,而是

7.21.1.p1表示

header string.h声明了一个类型和几个函数,以及 定义一个宏,该宏用于操作字符类型和 其他被视为字符类型数组的对象

并且
memcpy
在string.h中。
因此,我假设
memcpy
确实将参数视为字符数组。
因为所提到的宏是
NULL
,所以句子中的“有益于…”部分显然适用于函数。

将结束指针传递给
memmove
的第一个参数有几个陷阱,可能会导致鼻恶魔攻击。 严格地说,没有不透水的保证可以很好地定义

(不幸的是,标准中没有太多关于“超过最后一个元素”的信息。)

注意:很抱歉现在有另一个方向

基本的问题是,如果移动了0个字节,则“结束指针后的一个”是否是
memmove
的有效第一个函数参数:

T array[length];
memmove(array + length, array + length - 1u, 0u);
所讨论的要求是第一个论点的有效性

N1570,7.1.4,1

如果函数参数被描述为数组,则实际传递给函数的指针的值应确保所有地址计算和对对象的访问(如果指针确实指向该数组的第一个元素,则该值将是有效的)实际上都是有效的

如果函数的参数具有无效值(例如函数域外的值,或程序地址空间外的指针,或空指针,或对应参数不符合常量条件时指向不可修改存储的指针)或类型(升级后)参数个数可变的函数不需要该行为,但该行为未定义

如果指针

  • 不在地址空间之外
  • 不是空指针
  • 不是指向常量内存的指针
  • 如果参数类型为

  • 不是数组类型
  • 1.地址空间 N1570,6.5.6,8 此外,如果表达式p指向数组对象的最后一个元素,表达式(p)+1指向数组对象的最后一个元素,如果表达式Q指向数组对象的最后一个元素,则表达式(Q)-1指向数组对象的最后一个元素

    N1570,6.5.6,9 此外,如果表达式p指向数组对象的一个元素或数组对象最后一个元素的过去一个元素,并且表达式Q指向同一数组对象的最后一个元素,则表达式((Q)+1)-(p)的值与((Q)-(p))+1和as-((p)-(Q)+1)的值相同,如果 表达式P指向数组对象的最后一个元素,即使表达式(Q)+1未指向数组对象的元素。106

    106实现指针算术的另一种方法是首先将指针转换为字符指针:在该方案中,向转换后的指针添加或减去的整数表达式首先乘以最初指向的对象的大小,并将生成的指针转换回原始类型。对于指针减法,字符指针之间的差的结果类似地除以
    int a ;
    int* p = a+1 ;