M.M*_*M.M 11 c arrays strlen multidimensional-array language-lawyer
这是我的代码:
#include <string.h>
#include <stdio.h>
typedef char BUF[8];
typedef struct
{
BUF b[23];
} S;
S s;
int main()
{
int n;
memcpy(&s, "1234567812345678", 17);
n = strlen((char *)&s.b) / sizeof(BUF);
printf("%d\n", n);
n = strlen((char *)&s) / sizeof(BUF);
printf("%d\n", n);
}
Run Code Online (Sandbox Code Playgroud)
在任何优化级别上使用gcc 8.3.0或8.2.1,但在我期望的时候-O0输出。编译器决定将限制于,因此永远不能等于或超过被除以的值。0 22 2strlenb[0]
这是我的代码中的错误还是编译器中的错误?
标准中并未明确阐明这一点,但是我认为指针来源的主流解释是,对于任何对象X,代码(char *)&X都应生成一个可以迭代整个对象的指针X-即使X碰巧具有子数组作为内部结构。
(奖金问题,是否有gcc标志来关闭此特定优化?)
我检查了这一点,它在gcc 8.3-O1上重现,所以我只是在这里打开 gcc 优化标志列表并开始一一试验它们。事实证明,仅禁用稀疏条件常数传播可以使问题消失(幸运的是,如果一一测试没有结果,我计划测试几个标志)。-fno-tree-ccp
然后我切换到-O2但没有擦除-fno-tree-ccp标志。又重现了。我说“好的”,然后开始测试其他-O2标志。再次看来,禁用单个值范围传播还会导致预期的2 2输出。\n然后我删除了第一个-fno-tree-ccp标志,但它再次开始复制。因此,-O2您可以指定-O2 -fno-tree-ccp -fno-tree-vrp使您的程序按预期工作。
我没有删除这些标志,而是切换到了-O3那时。问题没有重现。
所以 gcc 8.3 中的这两种优化技术都会导致这种奇怪的行为(也许它们在内部使用了一些常见的东西):
\n我不赞成解释那里发生了什么以及为什么发生,也许其他人可以解释。但可以肯定的是,您可以指定-fno-tree-ccp -fno-tree-vrp标志来禁用这些优化技术,以便您的代码按预期工作。
\xe2\x80\x9c越努力,就越幸运。\xe2\x80\x9d \n\xe2\x80\x93 Samuel Goldwyn
\n编辑
\n正如@KamilCuk在问题评论中指出的那样,也会导致预期的行为,因此很可能在内置和另一种优化的-fno-builtin-strlen组合中存在编译器错误,其目的是切断死代码,静态确定可能的表达式值并通过传播常量一个程序。我认为编译器很可能错误地将某些确定其实现中的字符串长度(可能与整数除法和/或二维数组结合)的东西视为死代码,并在编译时将其截断或计算为 0。因此,我决定稍微研究一下代码来检查理论并消除该错误的其他可能的“参与者”。我看到了这个最小的行为例子,它证实了我的想法:strlenstrlen
int main()\n{\n // note that "7" - inner arrays size, you can put any other number here\n char b[23][7]; // local variable, no structs, no typedefs\n memcpy(&b[0][0], "12345678123456781234", 21);\n\n printf("%d\\n", strlen(&b[0][0]) / 8); // greater than that "7" !!!\n printf("%d\\n", strlen(&b[0][0]) / 7);\n printf("%d\\n", strlen(&b[0][0]) / 6); // less than that "7" !!!\n printf("%d\\n", strlen(&b[0][0])); // without division\n}\nRun Code Online (Sandbox Code Playgroud)\n\n\n0
\n
\n\n0
\n
\n\n3
\n
\n\n20
\n
我认为我们可以认为这是gcc中的一个错误。
\n我认为这-fno-builtin-strlen是解决该问题的更好方法,因为它仅适用于所有优化级别,并且内置的strlen优化技术似乎不太强大,特别是如果您的程序不使用strlen()很多。仍然-fno-tree-ccp -fno-tree-vrp也是一个选择。
| 归档时间: |
|
| 查看次数: |
168 次 |
| 最近记录: |