在C,C ++和Java吊装/重新排序:必须变量声明永远是在上下文顶部? [英] Hoisting/Reordering in C, C++ and Java: Must variable declarations always be on top in a context?

查看:96
本文介绍了在C,C ++和Java吊装/重新排序:必须变量声明永远是在上下文顶部?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我读了一些关于<一个href=\"http://stackoverflow.com/questions/11430095/are-hoisting-and-reordering-the-same-thing\">hoisting和重新排序,如此看来,Java虚拟机可以选择葫芦一些前pressions。我也了解Javascript中的函数声明提升。

I read a little about hoisting and reordering, so it seems that Java VM may choose to hoist some expressions. I also read about hoisting of function declarations in Javascript.

第一个问题:
有人可以确认是否在C,C ++和Java冲顶通常存在吗?或者是他们所有的编译器/优化依赖?

First Question: Can someone confirm if hoisting usually exist in C, C++ and Java? or are they all compiler/optimization dependent?

我读了很多例子C codeS始终把变量声明之上的,任何的断言边界条件之前的。我认为这将是一个快一点做的所有的断言的和的边界情况的变量声明之前给出该功能可以只终止。

I read a lot of example C codes that always put variable declarations on top, before any assert or boundary condition. I thought it would be a little faster to do all the asserts and boundary cases before variable declarations given that the function could just terminate.

主要问题:
必须变量声明永远是在上下文顶部? (有没有在工作中提升吗?)抑或是编译器通过检查自动优化code这些独立的断言的和的边界情况的第一个(前无关变量声明)?

Main Question: Must variable declarations always be on top in a context? (is there hoisting at work here?) Or does the compiler automatically optimize the code by checking these independent asserts and boundary cases first (before irrelevant variable declaration)?

下面是一个相关的例子:

Here's a related example:

void MergeSort(struct node** headRef) {
    struct node* a;
    struct node* b;
    if ((*headRef == NULL) || ((*headRef)->next == NULL)) {
        return;
    }
    FrontBackSplit(*headRef, &a, &b);
    MergeSort(&a);
    MergeSort(&b);
    *headRef = SortedMerge(a, b);
}

如上所示,边界的情况下不依赖于变量a和b的。因此,把上面的变量声明边界的情况下将使它稍微快一些?

As shown above, the boundary case does not depend on variables "a" and "b". Thus, putting the boundary case above variable declarations would make it slightly faster?

更新

上面的例子是不如我希望,因为变量A和B只申报,未初始化那里。直到我们真正需要使用它们的编译器会忽略声明。

The above example isn't as good as I hoped because variables "a" and "b" were only declared, not initialized there. Compiler would ignore declaration until we actually need to use them.

我检查与初始化变量声明GNU GCC程序集,程序集有不同的执行顺序。编译器并没有改变我的独立顺序的断言的和的边界情况的。 那么,这些重新排序的断言的和的边界情况的根本改变组件,从而改变如何整机运行它们。

I checked GNU GCC assemblies for variable declarations with initializations, the assemblies have different execution sequence. Compiler did not change my ordering of independent asserts and boundary cases. So, reordering these asserts and boundary cases do change the assemblies, thus changing how machine runs them.

我想不同的是微不足道的,大多数人从来没有关心这一点。

I suppose the difference is minuscule that most people never cared about this.

推荐答案

编译器可能重新排序/修改code,因为它愿意,只要如果按顺序执行修改后的code是等同于原始。所以曳引是允许的,但不是必需的。这是一个优化,这是完全编译特定

The compiler may reorder/modify your code as it wishes, as long as the modified code is equivalent to the original if executed sequentially. So hoisting is allowed, but not required. This is an optimization and it is completely compiler specific.

在C ++中声明变量可能是你想去的地方。在C语言中,他们曾经有过要在上下文之上,但引入了C99标准时,该规则是轻松,现在他们可以不管你想要的,类似于C ++。尽管如此,许多C程序员坚持把他们放在上面的内容。

Variable declarations in C++ can be wherever you wish. In C they used to have to be on top in a context, but when the c99 standard was introduced, the rules were relaxed and now they can be wherever you want, similarly to c++. Still, many c programmers stick to putting them on top in a context.

在您的例子中,编译器是免费的if语句移动到顶部,但我不认为它会。这些变量是刚刚被宣布栈是未初始化的指针,宣告他们的成本是最小的,而且它可能是更有效的在函数的开始创建它们,而不是认定后

In your example, the compiler is free to move the if statements to the top, but I don't think it would. These variables are just pointers that are declared on stack and are un-initialized, the cost of declaring them is minimal, moreover it might be more efficient to create them at the beginning of the function, rather than after the asserts.

如果您的声明将涉及任何副作用,例如:

If your declarations would involve any side-effects, for example

struct node *a = some_function();

那么编译器会在什么可以重新排序的限制。

then compiler would be limited in what it can reorder.

编辑:

我查了GCC的环吊装在实践中这个短节目:

I checked GCC's loop hoisting in practice with this short program:

#include <stdio.h>
int main(int argc, char **argv) {
    int dummy = 2 * argc;
    int i = 1;
    while (i<=10 && dummy != 4)
        printf("%d\n", i++);
    return 0;
}

我用这个命令编译它:

I've compiled it with this command:

gcc -std=c99 -pedantic test.c -S -o test.asm

这是输出:

    .file   "test.c"
    .def    ___main;    .scl    2;  .type   32; .endef
    .section .rdata,"dr"
LC0:
    .ascii "%d\12\0"
    .text
    .globl  _main
    .def    _main;  .scl    2;  .type   32; .endef
_main:
LFB7:
    .cfi_startproc
    pushl   %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    andl    $-16, %esp
    subl    $32, %esp
    call    ___main
    movl    8(%ebp), %eax
    addl    %eax, %eax
    movl    %eax, 24(%esp)
    movl    $1, 28(%esp)
    jmp L2
L4:
    movl    28(%esp), %eax
    leal    1(%eax), %edx
    movl    %edx, 28(%esp)
    movl    %eax, 4(%esp)
    movl    $LC0, (%esp)
    call    _printf
L2:
    cmpl    $10, 28(%esp)
    jg  L3
    cmpl    $4, 24(%esp)
    jne L4
L3:
    movl    $0, %eax
    leave
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
LFE7:
    .ident  "GCC: (GNU) 4.8.2"
    .def    _printf;    .scl    2;  .type   32; .endef

然后我用这个命令编译它:

Then I've compiled it with this command:

gcc -std=c99 -pedantic test.c -O3 -S -o test.asm

这是输出:

    .file   "test.c"
    .def    ___main;    .scl    2;  .type   32; .endef
    .section .rdata,"dr"
LC0:
    .ascii "%d\12\0"
    .section    .text.startup,"x"
    .p2align 4,,15
    .globl  _main
    .def    _main;  .scl    2;  .type   32; .endef
_main:
LFB7:
    .cfi_startproc
    pushl   %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    pushl   %ebx
    andl    $-16, %esp
    subl    $16, %esp
    .cfi_offset 3, -12
    call    ___main
    movl    8(%ebp), %eax
    leal    (%eax,%eax), %edx
    movl    $1, %eax
    cmpl    $4, %edx
    jne L8
    jmp L6
    .p2align 4,,7
L12:
    movl    %ebx, %eax
L8:
    leal    1(%eax), %ebx
    movl    %eax, 4(%esp)
    movl    $LC0, (%esp)
    call    _printf
    cmpl    $11, %ebx
    jne L12
L6:
    xorl    %eax, %eax
    movl    -4(%ebp), %ebx
    leave
    .cfi_restore 5
    .cfi_restore 3
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
LFE7:
    .ident  "GCC: (GNU) 4.8.2"
    .def    _printf;    .scl    2;  .type   32; .endef

所以基本上,与打开原来的code优化,转化是这样的:

So basically, with optimization turned on the original code was transformed to something like this:

#include <stdio.h>
int main(int argc, char **argv) {
    int dummy = 2 * argc;
    int i = 1;
    if (dummy != 4)
        while (i<=10)
            printf("%d\n", i++);
    return 0;
}

所以,你可以看到,确实是有提升的温度。

So, as you can see, there is indeed hoisting in C.

这篇关于在C,C ++和Java吊装/重新排序:必须变量声明永远是在上下文顶部?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆