restrict修饰的指针

-- TOC --

C99引入了restrict关键词,用来修饰指针。

概括的说,关键字restrict只用于限定指针。restrict告诉编译器,所有修改该指针所指向内容的操作全部都是基于(base on)该指针的,即不存在其它进行修改操作的途径;这样的效果是帮助编译器进行更好的代码优化,生成更有效率的汇编代码。

#include <stdio.h>


// __restrict is also OK
int func1(int *restrict a, int *restrict b){
    *a = 1;
    *b = 2;
    return *a + *b;
}


int func2(int *a, int *b){
    *a = 1;
    *b = 2;
    return *a + *b;
}


int main(void){
    int a,b;
    func1(&a, &b);
    func2(&a, &b);
    return 0;
}

我们来看看func1和func2在-O3时的汇编:

$ gcc -c test.c -O3
[xinlin@likecat test]$ objdump -d test.o

test.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <func1>:
   0:   c7 07 01 00 00 00       movl   $0x1,(%rdi)
   6:   b8 03 00 00 00          mov    $0x3,%eax
   b:   c7 06 02 00 00 00       movl   $0x2,(%rsi)
  11:   c3                      ret    

0000000000000020 <func2>:
  20:   c7 07 01 00 00 00       movl   $0x1,(%rdi)
  26:   c7 06 02 00 00 00       movl   $0x2,(%rsi)
  2c:   8b 07                   mov    (%rdi),%eax
  2e:   83 c0 02                add    $0x2,%eax
  31:   c3                      ret    

Disassembly of section .text.startup:

0000000000000000 <main>:
   0:   31 c0                   xor    %eax,%eax
   2:   c3                      ret    

由于func1的两个参数有restrict修饰,编译器对其代码进行了优化。编译器通过restrict修饰了解到,此时,能够修改*a指向内存的内容的,只有这里的a指针,因此,不管给*a赋值为何,这个值都不会被其它指针在其它地方修改,因此后面在做加法的时候,就可以不用再访问内存了(func2中的mov (%rdi),%eax指令,读取内容的值,存入eax寄存器)。

但,什么时候可以用restrict修饰指针,需要程序员明察秋毫!

memcpy的两个入参指针,都有restrict修饰,而memmove就没有。(参考memcpy和memmove的异同

gcc和g++都可识别__restrict-O3时都有优化效果,C/C++混编的时候,建议使用。

本文链接:https://cs.pynote.net/sf/c/202301161/

-- EOF --

-- MORE --