搜索
首页后端开发C++C 中晦涩难懂的'restrict”关键字

The Obscure “restrict” Keyword in C

介绍

除此之外,C99 添加了 limit 关键字,作为程序员指定指针是指向作用域中给定对象的唯一指针的一种方式,从而给编译器一个“提示” ”,当通过该指针访问对象时,它可能会执行额外的优化。

问题

为了说明限制要解决的问题,请考虑如下函数:

void update_ptrs( int *p, int *q, int const *v ) {
  *p += *v;
  *q += *v;
}

编译器将生成 x86-64 代码,例如:

mov eax, [rdx]  ; tmp = *v   // 1
add [rdi], eax  ; *p += tmp
mov eax, [rdx]  ; tmp = *v   // 3
add [rsi], eax  ; *q += tmp

你可能想知道为什么它生成第 3 行,因为它看起来与第 1 行是多余的。问题是编译器不知道你没有做这样的事情:

int x = 1, v = 2;
update_ptrs( &v, &x, &v );   // x = 5, v = 4

在 update_ptrs() 中,p 和 v 会别名 相同 int,因此编译器必须谨慎行事并假设 *v 的值可以在读取之间发生变化,因此需要额外的 mov 指令。

一般来说,C 中的指针会混淆优化,因为编译器无法知道两个指针是否彼此别名。 在性能关键的代码中,消除内存读取可能是一个巨大的胜利如果编译器可以安全地做到这一点。

解决方案

为了解决上述问题,C 中添加了 limit,允许您指定给定指针是 唯一 指向该指针作用域中的对象的指针,即同一作用域别名中没有其他指针它。

要使用限制,请将其插入声明中的 * 和指针名称之间。 重写为使用限制的 update_ptrs() 将是:

void update_ptrs_v2( int *restrict p, int *restrict q,
                     int const *restrict v ) {
  *p += *v;
  *q += *v;
}

(从右到左读取,例如 v 是指向常量 int 的受限指针;或使用 cdecl。)

通过添加限制,编译器现在可以生成如下代码:

mov eax, [rdx]  ; tmp = *v
add [rdi], eax  ; *p += tmp
add [rsi], eax  ; *q += tmp

现在,编译器能够删除附加 mov 指令的前第 3 行。

也许最知名的使用restrict的例子是标准库函数memcpy()。 这是复制内存块的最快方法如果源地址和目标地址重叠。当地址 重叠时,可以使用稍慢的 memmove() 函数。

陷阱

滥用限制会导致未定义的行为,例如,将 do 彼此别名的指针传递给 update_ptrs_v2() 或 memcpy()。 在某些情况下,编译器可以警告您,但并非在所有情况下,因此不要依赖编译器来捕获误用。

请注意,restrict 是针对给定范围的。 将一个受限制的指针分配给同一范围内的另一个会导致未定义的行为:

void f( int *restrict d, int *restrict s ) {
  int *restrict p = s;    // undefined behavior

但是,您可以将受限制的指针分配给不受限制的指针:

void f( int *restrict d, int *restrict s ) {
  int *p = s;             // OK

即使 p 不受限制,编译器仍然可以执行相同的优化。

也可以将内部作用域中的受限指针分配给外部作用域中的另一个受限制指针(但反之则不然):

void f( int *restrict d, int *restrict s ) {
  {                       // inner scope
    int *restrict p = s;  // OK
    // ...
    s = p;                // undefined behavior
  }
}

何时(以及何时不)使用限制

首先,您绝对应该分析您的代码(甚至可能查看生成的汇编代码),看看使用限制是否确实能够带来显着的性能改进,以证明冒潜在陷阱的风险是合理的。 诊断因滥用限制而导致的错误非常很难做到。

其次,如果限制的使用仅限于实现通过受限指针访问的内存由you分配的函数,那么它会更安全。 例如,给定:

void safer( unsigned n ) {
  n += n % 2 != 0;  // make even by rounding up
  int *const array = malloc( n * sizeof(unsigned) );
  unsigned *restrict half_1st = array;
  unsigned *restrict half_2nd = array + n/2;
  // ...
  free( array );
}

代码可以安全地对数组的前半部分和后半部分进行操作,因为它们不重叠(假设您从未访问 half_1st[n/2] 或更多)。

第三,如果在函数的参数中使用restrict,那么它可能不太安全。 例如,将 Safer() 与 update_ptrs_v2() 进行对比,其中 调用者 控制指针。 据所知,调用者错误并传递了别名的指针。

各种各样的

只有指向对象(或void)的指针可以用restrict限定:

restrict int x;       // error: can't restrict object
int restrict *p;      // error: pointer to restrict object
int (*restrict f)();  // error: pointer-to-function

可以对结构体成员使用restrict,例如:

struct node {
   void *restrict data;
   struct node *restrict left;
   struct node *restrict right;
};

表示 data 将是指向该数据的唯一指针,并且 left 和 right 永远不会指向同一个节点。 然而,对结构成员使用限制是非常不常见的。

最后,C++ 没有有限制。 为什么不呢? 答案很长,但 TL;DR 版本是:

  • 它可能是 C++ 委员会不想从 C 导入的难以发现的错误的来源。
  • C++ 越来越多地使用指针,例如这个,使得安全使用限制变得更加困难。

但是,许多编译器都有 __restrict__ 作为扩展。

结论

在有限的情况下,使用限制可以提高性能,但也存在一些重大缺陷。 如果您正在考虑使用限制,请先分析您的代码。

明智地使用。

以上是C 中晦涩难懂的'restrict”关键字的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
c语言函数返回值的类型有哪些?返回值是由什么决定的?c语言函数返回值的类型有哪些?返回值是由什么决定的?Mar 03, 2025 pm 05:52 PM

本文详细介绍了C函数返回类型,包括基本(int,float,char等),派生(数组,指针,结构)和void类型。 编译器通过函数声明和返回语句确定返回类型,执行

Gulc:从头开始建造的C库Gulc:从头开始建造的C库Mar 03, 2025 pm 05:46 PM

Gulc是一个高性能的C库,优先考虑最小开销,积极的内衬和编译器优化。 其设计非常适合高频交易和嵌入式系统等关键应用程序,其设计强调简单性,模型

c语言函数格式字母大小写转换步骤c语言函数格式字母大小写转换步骤Mar 03, 2025 pm 05:53 PM

本文详细介绍了字符串案例转换的C功能。 它可以通过ctype.h的toupper()和tolower()解释,并通过字符串迭代并处理零终端。 常见的陷阱,例如忘记ctype.h和修改字符串文字是

c语言函数的定义和调用规则是什么c语言函数的定义和调用规则是什么Mar 03, 2025 pm 05:53 PM

本文解释了C函数声明与定义,参数传递(按值和指针),返回值以及常见的陷阱,例如内存泄漏和类型不匹配。 它强调了声明对模块化和省份的重要性

c语言函数返回值在内存保存在哪里?c语言函数返回值在内存保存在哪里?Mar 03, 2025 pm 05:51 PM

本文研究C函数返回值存储。 较小的返回值通常存储在寄存器中以备速度;较大的值可能会使用指针来记忆(堆栈或堆),影响寿命并需要手动内存管理。直接ACC

distinct用法和短语分享distinct用法和短语分享Mar 03, 2025 pm 05:51 PM

本文分析了形容词“独特”的多方面用途,探索其语法功能,常见的短语(例如,“不同于”,“完全不同”),以及在正式与非正式中的细微应用

如何有效地使用STL(排序,查找,转换等)的算法?如何有效地使用STL(排序,查找,转换等)的算法?Mar 12, 2025 pm 04:52 PM

本文详细介绍了c中有效的STL算法用法。 它强调了数据结构选择(向量与列表),算法复杂性分析(例如,std :: sort vs. std vs. std :: partial_sort),迭代器用法和并行执行。 常见的陷阱

C标准模板库(STL)如何工作?C标准模板库(STL)如何工作?Mar 12, 2025 pm 04:50 PM

本文解释了C标准模板库(STL),重点关注其核心组件:容器,迭代器,算法和函子。 它详细介绍了这些如何交互以启用通用编程,提高代码效率和可读性t

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
2 周前By尊渡假赌尊渡假赌尊渡假赌
仓库:如何复兴队友
4 周前By尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒险:如何获得巨型种子
3 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具