我正在尝试了解更多关于程序集的信息,以及编译器可以做什么和不能做什么优化。
我有一段测试代码,对此我有一些问题。
在此处查看其实际操作:https://godbolt.org/z/pRztTT,或检查下面的代码和程序集。
#include <stdio.h>
#include <string.h>
int main(int argc, char* argv[])
{
for (int j = 0; j < 100; j++) {
if (argc == 2 && argv[1][0] == '5') {
printf("yes\n");
}
else {
printf("no\n");
}
}
return 0;
}
GCC 10.1 生产的 -O3 组件:
.LC0:
.string "no"
.LC1:
.string "yes"
main:
push rbp
mov rbp, rsi
push rbx
mov ebx, 100
sub rsp, 8
cmp edi, 2
je .L2
jmp .L3
.L5:
mov edi, OFFSET FLAT:.LC0
call puts
sub ebx, 1
je .L4
.L2:
mov rax, QWORD PTR [rbp+8]
cmp BYTE PTR [rax], 53
jne .L5
mov edi, OFFSET FLAT:.LC1
call puts
sub ebx, 1
jne .L2
.L4:
add rsp, 8
xor eax, eax
pop rbx
pop rbp
ret
.L3:
mov edi, OFFSET FLAT:.LC0
call puts
sub ebx, 1
je .L4
mov edi, OFFSET FLAT:.LC0
call puts
sub ebx, 1
jne .L3
jmp .L4
GCC似乎产生了两个版本的循环:一个具有argv[1][0]=='5'
条件但没有argc==2
条件,另一个没有任何条件。
我的问题:
GCC不知道< code>printf不会修改< code>argv指向的内存,所以它不能将检查抛出循环。
argc
是一个局部变量(不能被任何指针全局变量指向),因此它知道调用不透明函数不能修改它。证明局部变量是真正私有的是Escape Analysis的一部分。
OP通过首先将argv[1][0]
复制到本地char变量中来测试这一点:这让GCC将完整条件从循环中提升出来。
在实践中,argv[1]
不会指向打印f
可以修改的内存。但是我们只知道,因为printf
是一个C标准库函数,我们假设main
只是由CRT启动代码用实际的命令行args调用的。不是通过此程序中传递其自身参数的其他函数。在C中(与C不同),main
是重入的,可以从程序中调用。
此外,在GNU C中,printf
可以在其中注册自定义格式字符串处理函数。尽管在这种情况下,编译器内置的printf
查看格式字符串并将其优化为put
调用。
因此,printf
已经部分特殊,但我不认为GCC会费心去寻找基于它的优化,而不是修改任何其他全局可访问的内存。使用自定义 stdio 输出缓冲区,这甚至可能不是真的。打印速度
很慢;节省一些溢出/重新加载它周围通常没什么大不了的。
(理论上)将puts()和main()一起编译会让编译器看到puts()没有触及argv并完全优化循环吗?
是的,例如,如果您编写了自己的write
函数,该函数在系统调用
instruction周围使用内联asm语句(使用仅内存输入的操作数以确保安全,同时避免
撞击),那么它可以内联,并假设
argv[1]。
或者在没有内联的情况下进行过程间优化。
Re: 展开:这很奇怪,默认情况下,GCC 在 -O3
处不启用 -funroll-循环
,而只使用 -O3 -f轮廓使用
。或者,如果手动启用。
同样的for循环语句,在spring环境中执行和不在spring环境中执行,耗时不同。 代码的for循环是一个常用的用key加密文件的方法 在spring中执行耗时 controller耗时:399 controller耗时:368 controller耗时:367 controller耗时:366 controller耗时:368 controller耗时:367 controller耗时:36
今天我开始玩分支,检查两个布尔值。我很确定,在某些优化级别上,它们将简单地添加并检查,但gcc和CLANG不是这样。为什么gcc不优化两个bool检查,用addition和一个check替换它们?让我给你看一个例子: 两个分支(test+je)不应该比加法和分支(add+jne)慢吗? 编辑:我真正的意思是乘法,因为在true和false的情况下(1+0),加法给出true(1),但乘法给出正确的
在玩代码时,我注意到一个奇怪的行为,我不知道如何解释背后的逻辑 我希望执行次。然后我看到它继续运行(想象是100000而不是10),并且假设开发人员(VS)将(这是意料之中的),因此每次进入时输出都是次。 但后来证明从未初始化。 所以我的问题是为什么?这是一种未定义的行为吗?这不是一个标准的代码吗?
} 链接:https://www.hackerrank.com/challenges/java-string-compare/problem
我正在构建一个gradebook来存储学生和教师,每个学生和教师都有一个唯一的ID,以及他们各自在Student和Teacher对象的ArrayList中注册或教学的类。我有文件夹路径“j:/compsci/类/”,为每个类存储一个文本文件。 文本文件格式: 第1行:班级名称、教师ID、期间、荣誉?、班级ID 第2行:班级中每个学生的学生ID(用逗号分隔)。 在这里,我初始化了每个学生正在接受的所
我对python中双for循环的使用感到困惑,这是我的代码: 输出如下: 它只对外循环的第一个值执行内循环,为什么会发生这种情况?我怎样才能让它在第一个和第二个变量的所有组合上循环?