只是想知道:当我加限制的指针,我告诉编译器的指针不是一个别名,对另一个指针。让我们假设我有一个函数,如:

// Constructed example
void foo (float* result, const float* a, const float* b, const size_t size)
{
     for (size_t i = 0; i < size; ++i)
     {
         result [i] = a [0] * b [i];
     }
}

如果编译器必须假设 result 可能会重叠 a, 它已重新提取了各个时间。但是,正如 a 标记 const, 编译器也可以假设,一个是固定的,因此获取它一旦确定。

问题是,在这样的情况下,有什么建议的工作方式有限制?我当然不希望编译器,以重新获取 a 每一次,但我找不到良好的信息关于如何 restrict 应该是在这里工作。

有帮助吗?

解决方案

您指针常量,见人就叫你的功能,你不会碰这是指向通过该变量的数据。不幸的是,编译器仍然不会知道结果是常量指针的别名。您可以随时使用非const指针作为一个const指针。例如,很多功能需要一个const char(即字符串)的指针作为参数,但你可以,如果你愿意,它传递一个非const指针,该功能仅让你,它不会使用特定的一个承诺指针任何改变。

基本上,更贴近你的问题,你需要为了限制添加到A和B“承诺”,凡使用该功能将无法在结果传递作为别名为A或B的编译器。假设,当然,你可以做这样的承诺。

其他提示

每个人都在这里似乎很困惑。这里没有在迄今任何回答一个const指针的单个例子。

声明const float* a是的一个const指针,它的常量存储。指针仍然是可变的。 float *const a是一个const指针一个可变的浮动。

因此,问题应该是,是否有在float *const restrict a任何点(或const float *const restrict a如果您愿意)。

是的,你需要的限制。 指针const并不意味着没有什么可以改变的数据,只是你不能改变它通过的指针.

const 大多只是一个机构的要求编译器,来帮助你继续跟踪这东西你想要功能应允许修改。 const 是不是一个承诺编译器,一个能真的不会修改的数据.

不像 restrict, 使用的指针到const 到可变数据基本上是一个承诺其他人,不要编译器。铸造走 const 所有的地方不会导致错误的行为优化器(据我所知),除非你试图修改的东西,编译器放在只读存储器(见下文有关 static const 变量)。如果编译器不能看到的定义的一种功能时优化,它认为它蒙上走 const 和修改的数据通过这一指针(即那功能不尊重的 const斯的其指args).

编译器不会知道 static const int foo = 15; 不能改变,虽然和可靠地将内联的价值,甚至如果你通过其地址以未知的功能。(这是为什么 static const int foo = 15; 是不是比较慢 #define foo 15 对于优化编译器。好的编译器将优化这样一个 constexpr 只要有可能。)


记住, restrict 是的承诺,以编译器,事情你接通过这一指针不重叠与其他任何东西.如果这不是真的,你的功能不一定会做什么你期望。例如不要叫 foo_restrict(buf, buf, buf) 操作。

以我的经验(与海湾合作委员会和铛), restrict 主要是有用的指针,储存通过。它不会伤害到把 restrict 你源指针,太多,但通常得到所有asm的改善有可能从把它放在就目标的指针(s),如果 所有 商店你能不是通过 restrict 指针。

如果你有任何的功能的电话在你的循环, restrict 在一个来源指针不会让铛(但不是海湾合作委员会)避免重新加载。看看 这些试验的情况下在Godbolt编译器explorer, ,具体而言,这一:

void value_only(int);  // a function the compiler can't inline

int arg_pointer_valonly(const int *__restrict__ src)
{
    // the compiler needs to load `*src` to pass it as a function arg
    value_only(*src);
    // and then needs it again here to calculate the return value
    return 5 + *src;  // clang: no reload because of __restrict__
}

gcc6.3(针对x86-64SysV ABI)决定继续 src (指针)在一个叫保留注册的跨职能调用,并重新加载 *src 后呼吁。无论是海湾合作委员会的算法中没有现货,优化的可能性,或是决定这是不是值得的,或海湾合作委员会开发的目的不是实施它,因为他们认为这是不安全的。。。但是,由于铛做的,我猜是 大概 法律根据的C11标准。

clang4.0优化本来仅负荷 *src 一旦,并保持价值,在一个呼叫保留注册的跨职能的呼吁。没有 restrict, 它不这样做,因为所谓的功能可能(作为一个副作用)的修改 *src 通过另一个指针。

呼叫者的这种功能可能通过该地址的一个全球性可变的,例如.但任何修改的 *src 比其他通过 src 指针将违反承诺, restrict 由于编译器。因为我们没通过 srcvalonly(), 编译器可以假设它不会修改的价值。

GNU方言的C允许使用 __attribute__((pure))__attribute__((const)) 宣布这一功能没有副作用, ,允许这种优化没有 restrict, 但是没有携带相当于ISO C11(据我所知).当然,允许功能的内联(通过把它放在一个标题的文件或使用LTO)还允许这类优化,并更好地为小型职能,特别是如果所谓的内部循环。


编译器一般都是非常积极的做优化,该标准允许,即使他们是令人惊讶的来一些程序员,并打破一些现有的安全代码发生的工作。(C是如此便携式的,很多事是不确定的行为的基本标准;最好的实现做定义的行为很多事情的标准叶为UB。) C不是一种语言,它的安全扔码在编译器,直到它不会你想要什么,而不检查,你在做它正确的方式(没有签署整数溢出,等等。)


如果你看x86-64个体和小型输出,用于编写您的功能(的问题),可以很容易地看到差别。我把它放在 该Godbolt编译器explorer.

在这种情况下,把 restricta 足以让铛提升机的负荷 a[0], 但不gcc。

float *restrict result, 两铛和海湾合作委员会,将提升机的载荷。

例如

# gcc6.3, for foo with no restrict, or with just const float *restrict a
.L5:
    vmovss  xmm0, DWORD PTR [rsi]
    vmulss  xmm0, xmm0, DWORD PTR [rdx+rax*4]
    vmovss  DWORD PTR [rdi+rax*4], xmm0
    add     rax, 1
    cmp     rcx, rax
    jne     .L5

# gcc 6.3 with   float *__restrict__ result
# clang is similar with const float *__restrict__ a but not on result.
    vmovss  xmm1, DWORD PTR [rsi]   # outside the loop
.L11:
    vmulss  xmm0, xmm1, DWORD PTR [rdx+rax*4]
    vmovss  DWORD PTR [rdi+rax*4], xmm0
    add     rax, 1
    cmp     rcx, rax
    jne     .L11

因此,在摘要, __restrict__ 在所有的指针,都保证不重叠与其他东西.


顺便说一句, restrict 只是一个关键词。一些支持C++编译器 __restrict____restrict 作为扩展,所以你应该 #ifdef 它在不知名的编译器。

由于

C-99标准(ISO / IEC 9899:1999(E))const * restrict的实例,例如,在节7.8.2.3:

的strtoimax和strtoumax功能

概要

#include <inttypes.h>
intmax_t strtoimax(const char * restrict nptr,
                   char ** restrict endptr, int base);
--- snip ---

因此,如果假设的标准将不提供这样一个例子,如果const *是多余到* restrict,那么它们是,事实上,不是冗余的。

由于前面的回答说,你需要添加“限制”。 我也想对你的情况发表评论说,“结果可能有重叠”。这是不是唯一的原因,编译器将检测到“A”可能会改变。它也可以通过具有指针“一”另一个线程改变。因此,即使你的功能并没有改变任何值,则编译器将仍然认为“A”可能会改变。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top