繁体   English   中英

指向可变修改类型的指针的指针算法

[英]Pointer arithmetic on pointers to variably-modified types

以下是有效的 C 代码吗? 天马行空

#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 类型的指针?

如果您的编译器支持 VLA,则发布的代码是有效的 C 代码。 请注意,C99 中引入的 VLA 在最新版本的 C 标准中已成为可选。

gccclang都能正确编译代码,可以使用Godbolt 的编译器资源管理器进行验证。

然而,如果n参数的值恰好为空, clang 会发出关于潜在未定义行为的警告,未能识别出这种情况已通过显式测试处理。 问题不是减法的值,但类型的大小,这将是0 ,如果n == 0 此警告并不是真正的错误,而是实施质量问题。

同样有争议的是,只有当ab指向同一个数组或刚好经过它的最后一个元素时才定义a - b 因此xy必须验证此约束并具有unsigned char (*)[n]或兼容类型。 此规则有一个例外,用于将任何类型作为字符类型的数组进行访问,因此将指针传递给相同的int数组是可以的,但以这种方式调用f将是不正确的(尽管可能无害):

int x, y;
ptrdiff_t dist = f(sizeof(int), &x, &y);

编译器可以自由地发布诊断消息来吸引程序员对潜在问题的关注,事实上,在许多情况下,对于初学者和高级程序员来说,这样的警告都是救命稻草。 诸如-Wall-Werror-Weverything类的编译器选项非常有用,但在这种特殊情况下,如果-Werror也处于活动状态,则需要添加-Wno-pointer-arith以允许clang编译此函数。

另请注意,使用 C89 函数可以获得相同的结果:

ptrdiff_t f89(size_t n, void *x, void *y)
{
    if (!n) return 0;
    unsigned char *a = x, *b = y;
    return (a - b) / n;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM