我曾经认为在C99中,即使函数f和g的副作用受到干扰,尽pipeexpression式f() + g()不包含序列点,但f和g将包含一些,所以行为会未指定:f()将在g()之前调用,或者在f()之前调用g()。 我不再那么肯定。 如果编译器内联函数(编译器可能决定执行哪个函数(即使这些函数没有声明为inline函数),然后重新排列指令呢? 可能有人得到上述两个不同的结果吗? 换句话说,这是不确定的行为? 这不是因为我打算写这样的东西,这是在静态分析器中为这样的陈述select最好的标签。
从我的系统上的手册页: void * memmove(void * dst,const void * src,size_t len); 描述 memmove()函数将len字节从stringsrc复制到stringdst。 这两个string可能重叠 ; 副本总是在一个非破坏性的 方式。 从C99标准: 6.5.8.5比较两个指针时,结果取决于指向对象的地址空间中的相对位置。 如果两个指向对象或不完整types的指针指向同一个对象,或者两个指向同一个数组对象的最后一个元素,则它们相等。 如果指向的对象是同一个聚合对象的成员,则稍后声明的结构成员的指针比结构中较早声明的成员的指针要多,指向具有较大下标值的数组元素的指针比指向同一数组元素的指针具有较低的下标值。 所有指向同一联合对象的成员的指针相等。 如果expression式P指向数组对象的元素,并且expression式Q指向相同数组对象的最后一个元素,则指针expression式Q+1将比P 。 在所有其他情况下,行为是不确定的 。 重点是我的。 参数dst和src可以转换为指向char指针,以减轻严格的别名问题,但是可以比较指向不同块的两个指针,以便在指向内部时按照正确的顺序进行复制同一块? 显而易见的解决scheme是if (src < dst) ,但是如果src和dst指向不同的块,那么它是不确定的。 “未定义”意味着你甚至不应该假设条件返回0或1(这在标准的词汇中被称为“未指定”)。 另一种方法是if ((uintptr_t)src < (uintptr_t)dst)至less没有被指定,但是我不确定标准是否保证当src < dst被定义时,它相当于(uintptr_t)src < (uintptr_t)dst) 。 指针比较是从指针算术定义的。 例如,当我阅读第6.5.6节的内容时,在我看来,指针运算可能与uintptr_t运算的方向相反,也就是说,如果p是char*types, ((uintptr_t)p)+1==((uintptr_t)(p-1) 这只是一个例子。 一般来说,将指针转换为整数时似乎很less有保证。 这是一个纯粹的学术问题,因为memmove与编译器一起提供。 实际上,编译器作者可以简单地将未定义的指针比较为未指定的行为,或者使用相关的编译指令来强制编译器正确编译它们的memmove 。 例如, 这个实现有这个片段: if ((uintptr_t)dst < […]