是否在C11中定义了memcpy(& a + 1,& b + 1,0)?

时间:2014-08-19 18:33:26

标签: c language-lawyer c11 gcc4.9

此问题遵循previous question关于memcpy(0, 0, 0)的定义的问题,该问题最终被确定为未定义的行为。

正如相关问题所示,答案取决于C11第7.1.4条的内容:1

  

除非在以下详细说明中另有明确说明,否则以下每个陈述都适用:如果函数的参数具有无效值(例如函数域外的值,或者地址空间外的指针)程序或空指针,[...]行为未定义。 [...]

标准函数memcpy()需要指向voidconst void的指针,如下所示:

void *memcpy(void * restrict s1, const void * restrict s2, size_t n);

这个问题值得一提,因为标准中有两个“有效”指针的概念:有些指针可以通过指针算术有效地获得,并且可以有效地与<进行比较, >到同一对象内的其他指针。并且有一些指针可用于解除引用。前一类在以下代码段中包含“一次性”指针,例如&a + 1&b + 1,而后一类不包含这些指针有效。

char a;
const char b = '7';
memcpy(&a + 1, &b + 1, 0);

如果将上述片段视为已定义的行为,鉴于memcpy()的参数无论如何都被键入为void的指针,因此它们各自有效性的问题不能解除它们的引用。或者&a + 1&b + 1是否应被视为“在计划的地址空间之外”?

这对我很重要,因为我正在将标准C函数的效果形式化。我写了memcpy()作为requires \valid(s1+(0 .. n-1));的一个先决条件,直到我注意到GCC 4.9已开始aggressively优化此类库函数调用超出公式中表达的范围上面(indeed)。当\valid(s1+(0 .. n-1))true时,此特定规范语言中的公式n等同于0,并且不捕获GCC 4.9依赖于优化的未定义行为。

2 个答案:

答案 0 :(得分:18)

C11说:

  

(C11,7.24.2.1p2)“memcpy函数将s2指向的对象中的n个字符复制到s1指向的对象中。”

&a + 1本身是指向整数加法的有效指针,但&a + 1不是指向对象的指针,因此调用会调用未定义的行为。

答案 1 :(得分:5)

虽然&#34;正确&#34;根据标准的答案似乎不同意,我发现它只是在int之后的不诚实[6]; int b [6];全部

memcpy(a+0, b+0, 6);
memcpy(a+1, b+1, 5);
memcpy(a+2, b+2, 4);
memcpy(a+3, b+3, 3);
memcpy(a+4, b+4, 2);
memcpy(a+5, b+5, 1);

时,

应该有效(并复制一个以数组末尾结尾的区域)

memcpy(a+6, b+6, 0);

根据计数而不是地址有效。它是复制区域的同一端!

就个人而言,我倾向于定义memcpy(0,0,0)也是有效的(只需要有效指针但没有对象的理由)但至少它是一个奇怪的情况,而&#34;数组结束&#34; case是用于复制数组末尾区域的常规模式的实际例外。

相关问题