c - 有没有办法告诉 C 编译器指针没有别名存储?
问题描述
如果 C 编译器知道指针没有别名,它可以执行许多优化。例如,如果我编译以下函数gcc -O2
:
int f_noalias(int *arr, int x)
{
int res = 0;
int *p = &arr[17];
*p = x;
res += *p;
res += *p;
return res;
}
编译器知道读取*p
将始终评估为,x
因此生成的代码等效于为以下函数生成的代码:
int f_noalias2(int *arr, int x)
{
int *p = &arr[17];
*p = x;
return 2*x;
}
但是,如果编译器认为指针可能有别名,则不再执行此优化。例如,如果我们修改f
以便在读取 to 之间调用未知函数*p
,则生成的代码将取消引用p
两次。编译器假定该read_arr
函数可能已经修改了p
指向的值。
int f_withalias(int *arr, int x)
{
int res = 0;
int *p = &arr[17];
*p = x;
res += *p;
read_array(arr);
res += *p;
return res;
}
在我的特定程序中,当f
函数运行时p
,它持有的指针是唯一写入该arr
数组元素的指针。在这段时间内,代码中的其他函数可能会读取arr
,但不会写入。(他们可能会在完成运行arr
后写入其他值。)f
所以现在我有三个问题:
第一:有没有办法我可以声明我的变量来给 C 编译器这个提示?我尝试添加一个限制注释,p
但生成的代码gcc -O2
与生成的代码相同f_withalias
int f_restrict(int *arr, int x)
{
int res = 0;
int * restrict p = &arr[17];
*p = x;
res += *p;
read_array(arr);
res += *p;
return res;
}
第二:我在这里使用限制的尝试有效吗?我的理解是,restrict 意味着没有其他指针可以为 p 别名,无论是读取还是写入。但在我的情况下,该read_arr
函数显然也可以访问指向的arr
数组。p
第三:如果上一个问题的答案是“否”,我可以尝试一些不同的东西来代替restrict
吗?
基本上,我需要确保如果我这样做*p = x
,f
那么从arr[17]
. 但是,我希望 GCC 可以随意优化 tox = *p; y = *p
之类的东西x = *p; y = x
,即使两次读取之间存在函数调用。
解决方案
第一:有没有办法我可以声明我的变量来给 C 编译器这个提示?
int * restrict p = &arr[17];
断言 onlyp
和基于的指针表达式p
将用于p
在块的持续时间内访问任何指向的对象(不以任何方式修改的对象除外)。这可以优化res += *p;
您提出的建议。GCC 没有如此优化的事实是 GCC 中的一个质量问题。
第二:我在这里使用限制的尝试有效吗?…基本上,我需要确保如果我在 f 中执行 *p = x,那么从 arr[17] 读取的其他函数会立即注意到该写入。
后一个属性不是restrict
. p
声明restrict
和arr[17]
修改的事实意味着在执行包含 的块期间不应使用p
不基于的指针来访问,甚至不用于读取。因此,如果确实读取了某些内容(使用,而不是基于),则将违反断言。p
arr[17]
p
read_array
arr[17]
arr
p
restrict
推荐阅读
- python - 用 Python 下载 xlsx 文件
- javascript - 如何在一天的开始和一天结束时进入 .toDate() 对象?
- javascript - 如何在没有 jQuery 的情况下单击按钮打开 iframe
- android-jetpack-compose - 切换和取消切换 DropdownMenu 的外观
- html - css:在移动视图中将列显示为行
- python - Pydantic - 验证不会发生
- javascript - 输入“承诺”
' 必须有一个返回异步迭代器的 '[Symbol.asyncIterator]()' 方法 - elasticsearch - Elasticsearch 别名具有多个写入索引(不与任何其他问题重复)
- javascript - imported library function not defined from JavaScript webpack export
- java - 如何使 ChannelOutboundHandler.write() 方法异步?