使用-O2可缩短气泡排序C程序的时间

使用-O2可缩短气泡排序C程序的时间,c,sorting,gcc,bubble-sort,C,Sorting,Gcc,Bubble Sort,在linux shell上,使用gcc sort-o sort.c,然后使用time./sort>>out。 这里,如果我使用gcc-o2-sort-o-sort.c和类似的o3和o4,那么时间会不断减少。优化选项是如何工作的?请解释所有实时、用户时间和系统时间 PS:代码可能有点低效。请忽略这一点。-O代表优化,其中gcc将自动采取必要的步骤来优化您的程序。您可以在此处阅读有关GCC优化程序所采取的具体步骤的更多信息: 但本质上,-O2比-O1更优化,-O3比-O2更优化。这可能会带来编译二进

在linux shell上,使用gcc sort-o sort.c,然后使用time./sort>>out。 这里,如果我使用gcc-o2-sort-o-sort.c和类似的o3和o4,那么时间会不断减少。优化选项是如何工作的?请解释所有实时、用户时间和系统时间

PS:代码可能有点低效。请忽略这一点。

-O代表优化,其中gcc将自动采取必要的步骤来优化您的程序。您可以在此处阅读有关GCC优化程序所采取的具体步骤的更多信息:


但本质上,-O2比-O1更优化,-O3比-O2更优化。这可能会带来编译二进制大小方面的缺点,即生成的二进制文件可能会占用更多空间,但运行速度更快,反之亦然。实际上,您可以将代码粘贴到中,并在-O1或下拉列表旁边的任何优化选项中写入以选择编译器,godbolt将向您展示生成的代码的外观。您将能够看到O1和O2之间的差异,即O2生成的代码可能较短,并且将使用许多快捷方式来执行您的算法。

编译器标记控制您希望编译器执行的编译器优化量。简言之,构建项目需要更长的时间,但生成的可执行文件应该更快。有关详细信息,请在命令提示符或gcc-c-Q-O3-help=optimizers中键入man gcc,以获取有关为特定标志执行的优化的特定信息。

gcc提供了许多优化标志。您可以在这里看到每个人具体做了什么:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void sort();

int main() {
    int i;
    for (i = 0; i < 100000; i++) {
        sort();
    }
}

void sort() {
    int i, j, k, array[100], l = 99, m;
    for (i = 0; i < 100; i++) {
        array[i] = rand() % 1000 + 1;
    }
    for (k = 0; k < 99; k++) {
        for (j = 0; j < l; j++) {
            if (array[j + 1] > array[j]) {
                int temp = array[j];
                array[j] = array[j + 1];
                array[j + 1] = temp;
            }
        }
        l--;
    }
    for (m = 0; m < 100; m++) {
        printf("%d ", array[m]);
    }
}
优化总是有一个折衷办法,要么增加编译时间,要么增加内存使用,等等


-o2标志启用了几十种优化,因此可能无法立即确定哪些特定优化会影响排序。代替-o2,您可以单独尝试每个优化,例如使用-falign loops标志,以查看这是否是提供性能提高的优化。

优化选项在读取源代码和将二进制指令写入CPU之间起作用

GCC是一个多阶段编译器,其中阶段大致包括:

从输入文本创建标记。 将这些标记排列成抽象语法树结构。 修剪抽象语法树。 创建基于寄存器的指令,假设CPU寄存器数量无限。 将寄存器映射到实际可用的寄存器。 以加载程序预期的格式写入二进制信息。 优化可能会影响许多位置,通常在上述步骤3到5中它们会变为活动状态。有许多优化,包括:

常量折叠–预先计算常量子表达式。 强度降低–用更快的等效物取代缓慢的操作。 空序列–删除无用的操作。 组合操作–将多个操作替换为一个等效操作。 代数定律–使用代数定律简化或重新排序指令。 特殊情况指令–使用为特殊操作数情况设计的指令。 地址模式操作–使用地址模式简化代码。 循环展开-使用等效指令替换循环 部分循环展开-在保留整体功能的同时减少循环的计算次数。 请注意,这些不是可能执行的所有优化,但它开始给您一个想法

例如,如果编译器看到

https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
这些指令对我们人类来说可能更冗长,但CPU命令可能更小,因为不需要查找现在已擦除的s值,也不需要向其添加一个,或将新更新的值存储回RAM


GCC将优化分为不同的类别,从安全到风险-氧气是速度和安全之间的一个很好的折衷方案。更高的-O数风险更大。

是否注意到-O2、-O3和-O4优化选项的大写字母O?那么你不认为时间会减少吗?我不确定我是否理解这个问题。我认为您没有使用gcc sort-o sort.c,因为这会试图将sort编译为源代码,并将二进制文件写入sort.c。我认为您输入了gcc sort.c-o sort?换句话说:在执行时间方面,越少越好。@lower抱歉,问题是-o2,-o3 work-o2如何告诉编译器将其输出写入名为2的文件-O2支持优化。它们是完全不同的选择;因为gcc的选项区分大小写。另外,如果您真的在使用-o sort.c,那么您正在删除源文件。请更新您的问题,明确您实际使用的是哪一个;复制并粘贴精确的shell命令。避免命名变量l,因为它看起来太类似于1,尤其是程序员编辑器中使用的固定字体。主要GCC前端没有抽象语法树
从某种意义上说,for语句有一个树节点,或者if语句有一个树节点。@FlorianWeimer GCC有一个AST,不确定它是否是前端的一部分,但您可以通过GCC-fdump tree vcg-g test访问它。请注意,AST是用于GCC的,而不是用于正在解析的语言,所以我同意没有C if节点和Java if节点。而是AST驱动了他们的后端进程。我希望这能澄清一点,在我的表达中,我认为这是错误的理解。干杯-fdump树vcg用于转储CFG,它不是AST。C和C++前端都会向GOTOS控制较低的控制流结构。没有任何东西与原始语法非常相似。@FlorianWeimer我没有创建GCC,但我已经阅读了很多它的设计。是的,GCC中的AST不是特定于语言的AST,但我从未声称它是。它是一个AST,其设计使得单个后端可以处理各种语言前端。如果您曾经在汇编中编程,goto在JMP相关指令中有一个模拟,这是在汇编中通常执行选择性流控制的方式。您的上一个示例是否生成过类似puts3\n4\n5的代码?
int s = 3;
while (s < 6) {
   printf("%d\n", s);
   s++;
}
printf("%d\n", 3);
printf("%d\n", 4);
printf("%d\n", 5);