Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在C中循环n次而不进行比较_C++_C_Loops - Fatal编程技术网

C++ 在C中循环n次而不进行比较

C++ 在C中循环n次而不进行比较,c++,c,loops,C++,C,Loops,如果我知道有一个循环需要执行n次,有没有一种方法可以编写一个while(或for)循环而不需要每次进行比较?如果没有,是否有办法进行宏观转向: int i = 0; for(i = 0; i < 5; i++) { operation(); } 另外,这是我到目前为止想出的最快的循环 int i = 5; while(i-- >= 0) { operation(); } 一个足够聪明的编译器会帮你做到这一点。更具体地说,优化编译器理解循环展开。这是一个相当基本的优化,

如果我知道有一个循环需要执行n次,有没有一种方法可以编写一个while(或for)循环而不需要每次进行比较?如果没有,是否有办法进行宏观转向:

int i = 0;
for(i = 0; i < 5; i++) {
   operation();
}
另外,这是我到目前为止想出的最快的循环

int i = 5;
while(i-- >= 0) {
   operation();
}

一个足够聪明的编译器会帮你做到这一点。更具体地说,优化编译器理解循环展开。这是一个相当基本的优化,尤其是在编译时已知迭代次数的情况下


因此,简而言之:启用编译器优化,不要担心它。

两个循环都会进行比较

无论如何,编译器应该识别常量迭代并展开循环

您可以使用gcc和优化标志(-O)检查这一点,然后查看生成的代码

更重要的是:
除非有充分的理由,否则不要进行优化

在源代码中编写的指令数与编译器将生成的机器指令数没有严格的关系

大多数编译器更智能,在第二个示例中,它们可以生成如下代码:

operation();
operation();
operation();
operation();
operation();
while (count >= 5) {
    operation();
    operation();
    operation();
    operation();
    operation();
    count -= 5;
}
while (count > 0) {
    operation();
    count--;
}
自动执行,因为它们检测到循环将始终迭代5次

此外,如果您进行面向分析的优化,并且编译器发现一个循环有一个很小的主体和一个非常高的重复计数,那么它可能会展开它,即使是使用以下代码进行一般次数的迭代:

operation();
operation();
operation();
operation();
operation();
while (count >= 5) {
    operation();
    operation();
    operation();
    operation();
    operation();
    count -= 5;
}
while (count > 0) {
    operation();
    count--;
}
与原始版本相比,这将使大量的
count
s测试占大约五分之一

这是否值得做是只有分析才能判断的

如果您确信代码至少需要执行一次,那么可以做的一件事就是编写

do {
    operation();
} while (--count);
而不是

while (count--) {
    operation();
}
对于CPU来说,
count==0
的可能性有些恼人,因为大多数编译器生成的代码需要额外的JMP转发:

    jmp test
loop:
    ...operation...
test:
    ...do the test...
    jne loop
do{…}而
版本的机器代码只是

loop:
    ... opertion ...
    ... do the test...
    jne loop

一旦编译了C代码,while和for循环将转换为机器语言中的比较语句,因此无法避免使用for/while循环进行某种类型的比较。您可以创建一系列goto和算术语句,以避免使用比较,但结果可能效率较低。您应该研究如何使用radare2或gdb将这些循环编译成机器语言,以了解如何改进它们。

使用template,您可以使用如下方式展开循环(在编译时已知计数):

namespace detail
{

    template <std::size_t ... Is>
    void do_operation(std::index_sequence<Is...>)
    {
        std::initializer_list<std::size_t>{(static_cast<void>(operation()), Is)...};
    }

}

template <std::size_t N>
void do_operation()
{
    detail::do_operation(std::make_index_sequence<N>());
}
名称空间详细信息
{
模板
无效do_操作(标准::索引_序列)
{
std::初始值设定项列表{(static_cast(operation()),Is)…};
}
}
模板
void do_操作()
{
细节::do_操作(std::make_index_sequence());
}


但是编译器可能已经对普通循环进行了类似的优化。

您不应该这样做。如果编译器更有效的话,它已经展开了循环。为什么要这样做?它将在指令缓存中占用更多的空间,需要更多的指令解码,基本上情况会更糟。如果它更好,编译器不会为您转换它吗?(除非它是一块垃圾,在这种情况下你为什么要使用它?)你可以使用:
switch(count){case 4:operation();case 3:operation();case 2:operation();case 1:operation();}