C语言中restrict的意义,restrict关键字在C ++中的含义是什么?

正如其他人所说,如果C ++ 14中没有任何意义,那么让我们考虑一下__restrict__与C99相同的GCC扩展restrict。

C99

restrict说两个指针不能指向重叠的内存区域。最常见的用法是函数参数。

这限制了函数的调用方式,但允许更多的编译优化。

如果调用者不遵循restrict合同,则定义未定义的行为。

该C99 N1256草案 6.7.3 / 7 “类型的限定”说:

restrict限定符(如寄存器存储类)的预期用途是促进优化,并且从构成符合程序的所有预处理转换单元中删除限定符的所有实例不会改变其含义(即,可观察行为)。

和6.7.3.1“限制的正式定义”给出了血淋淋的细节。

可能的优化

的维基百科例子是非常照明。

它清楚地显示了它如何允许保存一个汇编指令。

没有限制:

void f(int *a, int *b, int *x) {

*a += *x;

*b += *x;

}

伪装配:

load R1 ← *x    ; Load the value of x pointer

load R2 ← *a    ; Load the value of a pointer

add R2 += R1    ; Perform Addition

set R2 → *a     ; Update the value of a pointer

; Similarly for b, note that x is loaded twice,

; because a may be equal to x.

load R1 ← *x

load R2 ← *b

add R2 += R1

set R2 → *b

有限制:

void fr(int *__restrict__ a, int *__restrict__ b, int *__restrict__ x);

伪装配:

load R1 ← *x

load R2 ← *a

add R2 += R1

set R2 → *a

; Note that x is not reloaded,

; because the compiler knows it is unchanged

; load R1 ← *x

load R2 ← *b

add R2 += R1

set R2 → *b

海湾合作委员会真的这样做吗?

g++ 4.8 Linux x86-64:

g++ -g -std=gnu++98 -O0 -c main.cpp

objdump -S main.o

有-O0,他们是一样的。

用-O3:

void f(int *a, int *b, int *x) {

*a += *x;

0:   8b 02                   mov    (%rdx),%eax

2:   01 07                   add    %eax,(%rdi)

*b += *x;

4:   8b 02                   mov    (%rdx),%eax

6:   01 06                   add    %eax,(%rsi)

void fr(int *__restrict__ a, int *__restrict__ b, int *__restrict__ x) {

*a += *x;

10:   8b 02                   mov    (%rdx),%eax

12:   01 07                   add    %eax,(%rdi)

*b += *x;

14:   01 06                   add    %eax,(%rsi)

对于没有经验的人,调用约定是:

rdi =第一个参数

rsi =第二个参数

rdx =第三个参数

GCC输出甚至比wiki文章更清晰:4条指令vs 3条指令。

数组

到目前为止,我们有单指令节省,但如果指针表示要循环的数组,一个常见的用例,那么可以保存一堆指令,如supercat和michael所述。

考虑例如:

void f(char *restrict p1, char *restrict p2, size_t size) {

for (size_t i = 0; i < size; i++) {

p1[i] = 4;

p2[i] = 9;

}

}

因为restrict,智能编译器(或人类)可以优化它:

memset(p1, 4, size);

memset(p2, 9, size);

哪个可能更高效,因为它可能在一个体面的libc实现(如glibc)上进行程序集优化?在性能方面使用std :: memcpy()或std :: copy()会更好吗?,可能有SIMD指令。

没有,限制,这种优化无法完成,例如考虑:

char p1[4];

char *p2 = &p1[1];

f(p1, p2, 3);

然后for版本:

p1 == {4, 4, 4, 9}

而memset版本使:

p1 == {4, 9, 9, 9}

海湾合作委员会真的这样做吗?

GCC 5.2.1.Linux x86-64 Ubuntu 15.10:

gcc -g -std=c99 -O0 -c main.c

objdump -dr main.o

有-O0,两者都是一样的。

用-O3:

限制:

3f0:   48 85 d2                test   %rdx,%rdx

3f3:   74 33                   je     428

3f5:   55                      push   %rbp

3f6:   53                      push   %rbx

3f7:   48 89 f5                mov    %rsi,%rbp

3fa:   be 04 00 00 00          mov    $0x4,%esi

3ff:   48 89 d3                mov    %rdx,%rbx

402:   48 83 ec 08             sub    $0x8,%rsp

406:   e8 00 00 00 00          callq  40b

407: R_X86_64_PC32      memset-0x4

40b:   48 83 c4 08             add    $0x8,%rsp

40f:   48 89 da                mov    %rbx,%rdx

412:   48 89 ef                mov    %rbp,%rdi

415:   5b                      pop    %rbx

416:   5d                      pop    %rbp

417:   be 09 00 00 00          mov    $0x9,%esi

41c:   e9 00 00 00 00          jmpq   421

41d: R_X86_64_PC32      memset-0x4

421:   0f 1f 80 00 00 00 00    nopl   0x0(%rax)

428:   f3 c3                   repz retq

两个memset电话如预期。

没有限制:没有stdlib调用,只是一个16迭代宽的循环展开,我不打算在这里重现:-)

我没有耐心对它们进行基准测试,但我相信限制版本会更快。

严格别名规则

该restrict关键字仅影响兼容类型的指针(例如两个int*),因为严格的别名规则表明,默认情况下,别名不兼容类型是未定义的行为,因此编译器可以假设它不会发生并优化掉。

请参阅:什么是严格别名规则?

它适用于参考?

根据海湾合作委员会的文件,它确实:https://gcc.gnu.org/onlinedocs/gcc-5.1.0/gcc/Restricted-Pointers.html语法:

int &__restrict__ rref

甚至还有this成员函数的版本:

void T::fn () __restrict__

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值