- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
考虑以下代码:
#include <string.h>
void bar(char c);
void foo(const char* restrict ss) {
for (int i = 0; i < strlen(ss); ++i) {
bar(*ss);
}
}
我希望 strlen(ss)
在这些基本理想的条件下被提升到循环之外;然而 - it isn't, neither by clang 5.0 nor by gcc 7.3最大优化 (-O3
)。
为什么会这样?
注意:灵感来自(我的回答)this question .
最佳答案
其他答案声称无法提升 strlen
调用,因为字符串的内容可能会在调用之间发生变化。这些答案没有正确解释 restrict
的语义;即使 bar
可以通过全局变量或其他机制访问字符串,restrict
指针到 const
类型的语义也应该 (请参阅警告) 禁止 bar
修改字符串。
来自 C11, N1570 draft, 6.7.3.1 :
1 Let D be a declaration of an ordinary identifier that provides a means of designating an object P as a restrict-qualified pointer to type T.
2 If D appears inside a block and does not have storage class extern, let B denote the block. If D appears in the list of parameter declarations of a function definition, let B denote the associated block. Otherwise, let B denote the block of main (or the block of whatever function is called at program startup in a freestanding environment).
3 In what follows, a pointer expression E is said to be based on object P if (at some sequence point in the execution of B prior to the evaluation of E) modifying P to point to a copy of the array object into which it formerly pointed would change the value of E.137) Note that ''based'' is defined only for expressions with pointer types.
4 During each execution of B, let L be any lvalue that has &L based on P. If L is used to access the value of the object X that it designates, and X is also modified (by any means), then the following requirements apply: T shall not be const-qualified. Every other lvalue used to access the value of X shall also have its address based on P. Every access that modifies X shall be considered also to modify P, for the purposes of this subclause. If P is assigned the value of a pointer expression E that is based on another restricted pointer object P2, associated with block B2, then either the execution of B2 shall begin before the execution of B, or the execution of B2 shall end prior to the assignment. If these requirements are not met, then the behavior is undefined.
5 Here an execution of B means that portion of the execution of the program that would correspond to the lifetime of an object with scalar type and automatic storage duration associated with B.
这里,声明D
是const char* __restrict__ ss
,关联的 block B
是foo<的主体
。 strlen
访问字符串的所有左值都具有基于 ss
(见警告) 的 &L
,并且这些访问发生在 B
执行期间(因为根据第 5 节中的定义,strlen
的执行是 B
执行的一部分)。 ss
指向一个 const 限定的类型,因此在第 4 节中,允许编译器假设 strlen
访问的字符串元素在 foo 的执行期间没有被修改
;修改它们将是未定义的行为。
(警告)上述分析假定 strlen
通过“普通”指针解引用或索引访问字符串。如果 strlen
使用 SSE 内在函数或内联汇编等技术,我不清楚此类访问在技术上是否算作使用左值来访问它指定的对象的值。如果它们不算在内,restrict
的保护可能不适用,并且编译器可能无法执行提升。
也许上述警告会使 restrict
的保护无效。也许编译器对 strlen
的定义了解不够,无法分析它与 restrict
的交互(我很惊讶它没有内联)。也许编译器可以自由执行提升,只是没有意识到;也许一些相关的优化没有实现,或者它未能在正确的编译器组件之间传播必要的信息。确定确切原因需要比我更熟悉 GCC 和 Clang 内部结构。
Further-simplified tests消除了 strlen
并且循环显示 Clang 确实支持 restrict-pointer-to-const 优化,但我无法从 GCC 观察到任何此类支持。
关于c - 为什么 gcc 和 clang 没有将 strlen 提升到这个循环之外?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48482003/
有一个 strlen 和一个 wcslen 函数,但是有一个模板字符数组长度函数,所以你可以做一些类似 strlen 的事情或 strlen ? 如果没有,那我想我会自己写。 最佳答案 你有 std:
我目前正在编写一个需要频繁比较字符串长度的 C 程序,所以我编写了以下帮助函数: int strlonger(char *s1, char *s2) { return strlen(s1) -
我有一些代码获取一个文件,将每一行读入一个新的字符串数组(并向每个字符添加 128),然后将每个数组分配给一个指针数组,然后打印每个数组。尝试运行代码时,我收到一条错误消息,指出由于以下原因导致的段错
假设我有一个大小相同的字符串数组。 char strings[][MAX_LENGTH]; strlen(strings) 和 strlen(*strings) 之间有什么区别? 我知道 string
我不知道是什么原因导致这个问题...感谢任何帮助!我已经尝试了很多 strlen 代码,但这是唯一一个我可以实现且只有 1 个错误的代码。使用此代码,我尝试从文件中读取字符串,将其分解为由空格分隔的单
我有这个代码: int main() { char ch[15]; cout<
所以我正在学习嵌入式系统类(class),我们正在使用 C 语言。现在是第 2 周,所以我们只是刷新我们的 C 代码内存。 这段代码是如何打印出数字 6 的?幕后发生了什么? int main (vo
这个问题在这里已经有了答案: What do the parentheses around a function name mean? (3 个答案) 关闭 8 年前。 在 bstrlib.c(bs
编码 strlen($a); } “正确”的解决方案,在所有版本中都能正常工作(至少自从引入了飞船运算符(operator)以来)。 https://3v4l.org/6XRYW 关于php - P
我说strlen没用出于效率目的。因为如果你使用strlen那么你已经迭代了一个字符串,并且最好的算法总是迭代给定的容器不超过一次。所以请帮助我思考如何实现一个功能 bool contains ( c
这个问题已经有答案了: error: conflicting types for built-in function ‘tolower’ [-Werror] (2 个回答) 已关闭 4 年前。 我正在
我很困惑。有什么区别: char *someFunction(char *src) { char str[strlen(src) + 1]; ... return str; }
我有以下来自数据库的字符串:Let's Get Functional 如果我通过 strlen 运行它,它会返回 25 个字符而不是预期的 20 个字符。var 转储显示字符串看起来像上面的字符串(没
我正在使用 C 字符串库的 strlen 函数。我传递了一个 NULL字符串并找到神秘的结果。我知道我不应该传递 NULL 字符串,但我需要一个解释。代码看起来像这样 main() { int k
此代码返回 n=11,第 10 个和第 11 个字符为 ' ' 和 '@' 这是如何运作的? strlen函数怎么把它当成11个字符?在某些编译器中,它似乎将字符串长度设为 12 个字符。 #incl
以下代码能够确定 DWORD 的一个或多个字节是否设置为 0。 mov eax, value mov edx, 07EFEFEFFh add edx, eax xor eax, 0FFFFFFFFh
我在这里找到解决方案时遇到问题。我正在为使用 for() 的客户开发 WordPress 主题。循环遍历页面标题,以便将其包装在 中s 并垂直显示.. 循环使用 strlen()找到标题的长度,但由
我在理解 strlen 和/或 memcpy 时遇到问题。这是片段: char * restP; char * str; //this returns a pointer restP = strrst
好的,我正在检查一个字符串是否至少有 4 个字符长且至少有 25 个字符短 我试过这样使用strlen $userNameSignupLength = strlen($userNameSignup);
#include #include #include int main(void) { char qq[] = {'a' , 'b' , 'c' , 'd'}; char qqq
我是一名优秀的程序员,十分优秀!