如果指针完全相同,C ++指针别名是否为威胁?

时间:2015-04-01 11:45:09

标签: c pointers restrict restrict-qualifier

考虑用于矢量化的这个函数:

void AddSqr(float* restrict dst, float* restrict src, int cnt)
{
    for (int i=0; i<cnt; i++) dst[i] = src[i] * src[i];
};

如果src&amp; dst当然没有别名。但是如果src == dst怎么办?当然不允许使用src == dst + 1等极端情况。但如果指针是相同的,那不应该是一个问题,或者我错过了什么?

编辑:restrict是Intel C ++编译器关键字,MSVC有__restrict。

我对这个问题的看法是,我没有看到任何类型的矢量化可能出错的方式:因为每个dst值都依赖于单个src值完全不同(没有任何别名)或完全不同相同的地址,当dst改变时,将永远不再需要src值,因为它已被写入的事实意味着已经计算了输出。唯一的情况是如果编译器使用dst本身作为临时缓冲区,我认为这甚至是不正确的。

3 个答案:

答案 0 :(得分:2)

在C中,您的代码违反restrict定义会导致未定义的行为,因为它通过dst写入一个对象,但通过src读取同一个对象。

dstsrc之间是否存在偏移量并不重要;条件是存在一个float对象,它通过一个指针写入并通过另一个指针读取。

答案 1 :(得分:0)

Restrict是一个关键字,允许一些优化只有在两个指针互不干扰的情况下才有效。

对于你非常简单的情况,当两个指针相同时,不可能有任何可用的优化失败,所以当你测试时不会发生任何不好的事情。

但是在更一般的情况下,restrict关键字意味着您断言两个指针是不同的,并且它们指向的数据结构是不同的。编译器可以自由地使用这个断言来允许它想要的任何优化,特别是那些如果你的断言不正确会使你的程序发生灾难性失败。

这种失败称为“未定义行为”,因为C标准没有定义断言错误时会发生什么。由于这是一个优化断言,完全不可预测的行为,通常被称为“鼻子恶魔”,是C编译器定义的合理行为。

答案 2 :(得分:0)

感谢所有回答的人。所以: - 通过标准C ++定义,这确实是错误的。 - 但我直接从英特尔那里得到了答复,这是可以的。

我原来的问题确实不是关于它是否“遵守规则”,而是否有可能出错。 src / dst数组以1:1的形式映射,因此数组完全不同,或者它们完全相同,因此每个项目要么依赖于某些完全不相关的项目,要么本身。因此,如果项目被重写,则其最终值已被计算存储,并且在循环期间将永远不再需要。

无论如何,我做了一些额外的处理:

void AddSqr(float* restrict dst, float* restrict src, int cnt)
{
    if (dst == src)
        for (int i=0; i<cnt; i++) dst[i] = dst[i] * dst[i];
    else
        for (int i=0; i<cnt; i++) dst[i] = src[i] * src[i];
};

这应该解决潜在的问题,甚至提供一些额外的优化可能性,因为在指针相同的情况下,编译器只能使用一个寄存器(或不使用偏移寄存器)来定位数组。