Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.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/C++;语句参数的内部算术运算_C++_C_For Loop_Constants_Compiler Optimization - Fatal编程技术网

C++ 在C/C++;语句参数的内部算术运算

C++ 在C/C++;语句参数的内部算术运算,c++,c,for-loop,constants,compiler-optimization,C++,C,For Loop,Constants,Compiler Optimization,假设我有以下代码: int v; setV(&v); for (int i = 0; i < v - 5; i++) { // Do stuff here, but don't use v. } 第二种样式会有所不同吗?编辑: 出于意想不到的原因,这是一个有趣的问题。更重要的是,编译器要避免出现意外的v别名这种迟钝的情况。如果编译器能够证明这不会发生(版本2),那么我们就可以得到更好的代码 这里的教训是更关注消除混叠,而不是尝试为它做乐观主义者的工作 制作拷贝cv实际上带来了

假设我有以下代码:

int v;
setV(&v);
for (int i = 0; i < v - 5; i++) {
  // Do stuff here, but don't use v.
}
第二种样式会有所不同吗?

编辑: 出于意想不到的原因,这是一个有趣的问题。更重要的是,编译器要避免出现意外的
v
别名这种迟钝的情况。如果编译器能够证明这不会发生(版本2),那么我们就可以得到更好的代码

这里的教训是更关注消除混叠,而不是尝试为它做乐观主义者的工作

制作拷贝cv实际上带来了最大的优化(省去了冗余内存获取),尽管乍一看它似乎(稍微)效率较低

原始答案和演示: 让我们看看:

鉴于:

extern void setV(int*);
extern void do_something(int i);

void test1()
{
    int v;
    setV(&v);
    for (int i = 0; i < v - 5; i++) {
    // Do stuff here, but don't use v.
      do_something(i);
    }
}


void test2()
{
    int v;
    setV(&v);
    const int cv = v;
    for (int i = 0; i < cv - 5; i++) {
      // Do stuff here. Changing cv is actually impossible.
      do_something(i);
    }  
}

第二种形式在这个编译器上更好。

我们希望编译器在这两种情况下都能对此进行优化。但其实只有一种方法可以找到答案。编译它并检查assembly.dependens。是否将
v
的地址传递给循环中的函数?如果是,功能是否在不同的翻译单元中?如果是这样,是否启用了链接时间优化?在我的实际程序中,v是由一个函数引用设置的几个变量之一。它从不在循环内部使用。我不知道如何检查编译后的代码。假设注释“don't use v”没有说谎,任何远程半生不熟的优化器都会检查
v
的使用情况。在第一个示例中,请参见表达式
v-5
从不更改,因为
v
从不更改,也不会将其置于可能更改的位置,并执行一次计算。如果不是这样的话,你的优化器就糟透了。编译到asm,如果你真的担心的话,请查看说明。@WhozCraig我会看看我是否能想出如何编译到asm。(并理解结果)我主要是好奇,而不是担心。我被要求编写高效的代码,但我不确定哪一个是最高效的。在循环之外设置值或这样做。无论如何,我希望能够支持我的决定。目前,我正在使用GCC,但最终它将在VC++上运行。我不知道VC++是否是半生不熟的。请记住,如果编译器没有使用整个程序优化,它就无法在第一种情况下优化掉求值,因为它不知道
v
setV
中没有别名,在
do\u something
中没有变异@MarkB v是函数的局部。没有从do_something(按值获取其参数)合法访问v的权限,因此编译器可以像在test2()中那样自由假设没有别名。
setV
获取本地
v
的地址,并将其粘贴到
全局_v_ptr
。然后
do\u something
通过
*global\u v\u ptr
访问
v
,并合法地更新局部变量。@MarkB是的,因此在test2中,我们向编译器证明调用和循环结束条件之间没有因果关系。这本身可能是在第二种形式中使用额外变量的一个成功论点i时进行编码>和迭代,为什么不设置cv=v-5并在
i
时进行交互?作为一名代码维护人员,如果我看到for构造中的数学知识,我会认为该表达式中的一个(或多个)变量可能会在循环中的某个位置发生变化,这可能是直接的,也可能是函数调用的副作用。
extern void setV(int*);
extern void do_something(int i);

void test1()
{
    int v;
    setV(&v);
    for (int i = 0; i < v - 5; i++) {
    // Do stuff here, but don't use v.
      do_something(i);
    }
}


void test2()
{
    int v;
    setV(&v);
    const int cv = v;
    for (int i = 0; i < cv - 5; i++) {
      // Do stuff here. Changing cv is actually impossible.
      do_something(i);
    }  
}
test1():
        pushq   %rbx
        subq    $16, %rsp
        leaq    12(%rsp), %rdi
        call    setV(int*)
        cmpl    $5, 12(%rsp)
        jle     .L1
        xorl    %ebx, %ebx
.L5:
        movl    %ebx, %edi
        addl    $1, %ebx
        call    do_something(int)
        movl    12(%rsp), %eax
        subl    $5, %eax
        cmpl    %ebx, %eax
        jg      .L5
.L1:
        addq    $16, %rsp
        popq    %rbx
        ret
test2():
        pushq   %rbp
        pushq   %rbx
        subq    $24, %rsp
        leaq    12(%rsp), %rdi
        call    setV(int*)
        movl    12(%rsp), %eax
        cmpl    $5, %eax
        jle     .L8
        leal    -5(%rax), %ebp
        xorl    %ebx, %ebx
.L12:
        movl    %ebx, %edi
        addl    $1, %ebx
        call    do_something(int)
        cmpl    %ebp, %ebx
        jne     .L12
.L8:
        addq    $24, %rsp
        popq    %rbx
        popq    %rbp
        ret