并帮助限制在C如果指针已标记const?
-
19-08-2019 - |
题
只是想知道:当我加限制的指针,我告诉编译器的指针不是一个别名,对另一个指针。让我们假设我有一个函数,如:
// 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
由于编译器。因为我们没通过 src
要 valonly()
, 编译器可以假设它不会修改的价值。
GNU方言的C允许使用 __attribute__((pure))
或 __attribute__((const))
宣布这一功能没有副作用, ,允许这种优化没有 restrict
, 但是没有携带相当于ISO C11(据我所知).当然,允许功能的内联(通过把它放在一个标题的文件或使用LTO)还允许这类优化,并更好地为小型职能,特别是如果所谓的内部循环。
编译器一般都是非常积极的做优化,该标准允许,即使他们是令人惊讶的来一些程序员,并打破一些现有的安全代码发生的工作。(C是如此便携式的,很多事是不确定的行为的基本标准;最好的实现做定义的行为很多事情的标准叶为UB。) C不是一种语言,它的安全扔码在编译器,直到它不会你想要什么,而不检查,你在做它正确的方式(没有签署整数溢出,等等。)
如果你看x86-64个体和小型输出,用于编写您的功能(的问题),可以很容易地看到差别。我把它放在 该Godbolt编译器explorer.
在这种情况下,把 restrict
上 a
足以让铛提升机的负荷 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”可能会改变。