以下的C代码是否有效?(godbolt)
#include <stddef.h>
ptrdiff_t f(size_t n, void *x, void *y)
{
if (!n) return 0;
typedef unsigned char element[n];
element *a = x, *b = y;
return a - b;
}
使用-Werror=pointer-arith
,clang会大声抱怨
<source>:8:14: error: subtraction of pointers to type 'element' (aka 'unsigned char [n]') of zero size has undefined behavior [-Werror,-Wpointer-arith]
return a - b;
~ ^ ~
当gcc编译代码时没有任何投诉。
clang认为发生了未定义的行为是什么?减法可能为零,因此不是数组元素的有效指针或其他情况?没有进行数组访问,对吧?那就不应该是这种情况...
如果代码确实表现出未定义的行为,是否有一种简单的方法可以修改代码以完全符合规范,同时仍然使用指向VM类型的指针?
typedef
不是问题所在。将a
和b
声明为unsigned char (*a)[n] = x, (*b)[n] = y;
会得到相同的结果。如果忽略警告(即删除-Werror
标志),该程序可以生成有效的输出。 - user3386109int f(void *x) { int n = 1; return (char (*)[n]) x - (char (*)[n]) x; }
来复现。这似乎是Clang中的一个错误。有趣的是,(char (*)[n]) x + 1
不会产生错误,因此Clang并不普遍认为char (*)[n]
的大小为零。这支持了这个猜想是一个bug,因为任何关于char (*)[n]
指针算术的C规则应该同样适用于添加指针和整数以及减去两个指针。 - Eric Postpischilqsort
示例的解决方案是从分区函数中返回j
。递归调用变为qsort(base,j+1,bytes,cmp)
和qsort(base+j+1,num-1-j,bytes,cmp)
。这消除了麻烦的指针减法。它可能也具有更好的性能,因为指针减法具有隐式除法,并且我认为在减去VLA指针时无法优化该除法。 - user3386109