---
# System prepended metadata

title: restrict
tags: [C basics]

---

# restrict 
###### tags: `C basics`

### Reference 
>致謝
>https://stackoverflow.com/questions/18726867/is-strcpy-where-src-dest-strictly-defined
>https://www.itread01.com/content/1542973983.html
>https://www.zhihu.com/question/41653775

### Basics
之前小生我在寫leetcode的時候，曾經想利用strcpy複製字串，而src和dest的字串有一部份位址是重疊的，當時就產生了這樣的錯誤 : *strncpy-param-overlap memory ranges leetcode*
令我十分不解，現在想起來真的很蠢，其實是我根本沒有好好看strcpy的定義。直到今天才發現定義好像跟我想的不一樣，怎麼多了一個restrict阿??

```c= 
#include <string.h>
char *strcpy(char *restrict s1, const char *restrict s2);
```

restrict in this case indicates that the caller promises that the two buffers in question do not overlap.
It says that for the lifetime of the pointer, only it or a value directly derived from it (such as pointer + 1) will be used to access the object to which it points.



restrict的出現是為了解決一種叫指標混淆Pointer aliasing的問題，並且**只用於指標的語法結構**，它的作用是作為型別限定詞，**表明指標是訪問一個數據物件的唯一且初始的方式。**

pointer aliasing是指兩個或兩個以上的指標指向同一數據，例如
```c= 
int i = 0;
int *a = &i;
int *b = &i;
```
如果編譯器不理會兩指標是否指向同一數據，不優化
```c= 
int foo(int *a, int *b){
    *a = 5;
    *b = 6;
    return *a + *b;     // 不一定是 11！
}
```

如果a和b都指向同一數據，會導致回傳值為12。
而**如果我們確定兩指標不指向同一數據，就可以用restrict修飾指標類型**
```c= 
int rfoo(int *restrict a, int *restrict b){
    *a = 5;
    *b = 6;
    return *a + *b;
}
```
**但如果用了restrict去修飾兩個指標，而他們在作用域内又指向同一地址，那麼會是未定義行為。**  
總而言之restrict是為了告訴編譯器額外信息（兩個指不指向同一數據）從而生成更優化的機器碼，因為編譯器是無法自行在編譯期間檢測兩個指標是否alias的。



使用restict有一些限制
```c= 
int a[5];    /* 陣列a */
/* p1是訪問由malloc分配的記憶體的唯一且初始的方式，可以用restrict */
int * restrict p1 = (int *)malloc(10 * sizeof(int));
/* p2既不是初始的，又不是訪問陣列a的唯一方式，不可再限定為restrict */
int * p2 = a;
```

最後也可以這樣理解，restrict目的是告知compiler，這一個restrict pointer是唯一指向data的指標，程式當中不會透過其他變數 (pointer、或者直接存取)來access此data。

其他在C99用到restrict的例子：
```c= 
void* memcpy (void* restrict destination, const void* restrict source, size_t n);
//代表destination和source區段是不可重疊的
 
FILE *fopen(const char *restrict pathname, const char *restrict type);
```