从size_t转换为int

时间:2013-05-14 11:21:12

标签: c assembly type-conversion

关注thread ...

对于这段代码:

#include <stdio.h>

int main(void)
{
    int i;
    size_t u;

    for (i = 0; i < 10; i++) {
        u = (size_t)i;
        printf("i = %d, u = %zu\n", i, u);
    }
    return 0;
}

汇编中的输出是:

编辑:使用-O2编译

    .file   "demo.c"
    .section    .rodata.str1.1,"aMS",@progbits,1
.LC0:
    .string "i = %d, u = %zu\n"
    .section    .text.startup,"ax",@progbits
    .p2align 4,,15
    .globl  main
    .type   main, @function
main:
.LFB3:
    .cfi_startproc
    pushq   %rbx
    .cfi_def_cfa_offset 16
    .cfi_offset 3, -16
    xorl    %ebx, %ebx
    .p2align 4,,10
    .p2align 3
.L2:
    movq    %rbx, %rdx
    movl    %ebx, %esi
    xorl    %eax, %eax
    movl    $.LC0, %edi
    addq    $1, %rbx
    call    printf
    cmpq    $10, %rbx
    jne .L2
    xorl    %eax, %eax
    popq    %rbx
    .cfi_def_cfa_offset 8
    ret
    .cfi_endproc
.LFE3:
    .size   main, .-main
    .ident  "GCC: (Debian 4.7.2-5) 4.7.2"
    .section    .note.GNU-stack,"",@progbits

转换u = (size_t)i;是否正在消耗额外的周期?

3 个答案:

答案 0 :(得分:5)

是的,因为代码已发布,当然。您的转换位于:

movl    -4(%rbp), %eax
cltq
movq    %rax, -16(%rbp)

当然,这段代码没有经过优化,所以这不是一个非常公平的比较。如果使用优化对其进行编译,编译器可能会意识到值始终为正,只需从保存第三个参数的任何寄存器i%rdx进行一次移动。

编辑:

如所怀疑的,优化代码中基本上没有开销。在这种情况下,编译器已将循环转换为向上计数u,并从i派生u而不是相反,因此%rbx用于循环,i的值仅使用%ebx,这是%rbx的低32位 - 因此在此示例中没有开销。我强调这一点,因为可能存在其他情况,从int转换为size_t将会受到惩罚。这完全取决于具体情况。

答案 1 :(得分:4)

是的,确实如此,因为它将内部表示从32位更改为64位。 具体来说,

.L3:
    movl    -4(%rbp), %eax
    cltq
    movq    %rax, -16(%rbp)
    movq    -16(%rbp), %rdx

读取i,执行符号扩展并复制到%rdx。我不确定为什么这个值必须通过堆栈 - 正如垫子所指出的,这看起来像是来自非优化编译器运行的代码。

修改

在优化的汇编代码中,循环计数器保持为更宽的数据类型。 afair,寄存器之间的mov在运行时周期中没有区别于四字或双字(实际上它们没有:见表{C-16 in intels pertinent doc,由this SO post引用。< / p>

答案 2 :(得分:2)

不确定这是否是为您消耗周期的实际分配 我相信这是消耗周期的任务

例如,

在这个t1.c

#include <stdio.h>

int main(void)
{
    int i;
    size_t u;

    for (i = 0; i < 10; i++) {
        printf("i = %d, u = %zu\n", i, u);
    }
    return 0;
}

和适用于t1.c

        .file   "t1.c"
        .section        .rodata
.LC0:
        .string "i = %d, u = %zu\n"
        .text
.globl main
        .type   main, @function
main:
        pushl   %ebp
        movl    %esp, %ebp
        andl    $-16, %esp
        subl    $32, %esp
        movl    $0, 24(%esp)
        jmp     .L2
.L3:
        movl    $.LC0, %eax
        movl    28(%esp), %edx
        movl    %edx, 8(%esp)
        movl    24(%esp), %edx
        movl    %edx, 4(%esp)
        movl    %eax, (%esp)
        call    printf
        addl    $1, 24(%esp)
.L2:
        cmpl    $9, 24(%esp)
        jle     .L3
        movl    $0, %eax
        leave
        ret
        .size   main, .-main
        .ident  "GCC: (GNU) 4.4.6 20110731 (Red Hat 4.4.6-3)"
        .section        .note.GNU-stack,"",@progbits

在上述情况下,现在没有任何分配

第二个案例t2.c

#include <stdio.h>

int main(void)
{
    int i;
    size_t u;

    for (i = 0; i < 10; i++) {
        i = (size_t) u;
        printf("i = %d, u = %zu\n", i, u);
    }
    return 0;
}

以及随后的恭喜

        .file   "t2.c"
        .section        .rodata
.LC0:
        .string "i = %d, u = %zu\n"
        .text
.globl main
        .type   main, @function
main:
        pushl   %ebp
        movl    %esp, %ebp
        andl    $-16, %esp
        subl    $32, %esp
        movl    $0, 24(%esp)
        jmp     .L2
.L3:
        movl    28(%esp), %eax
        movl    %eax, 24(%esp)
        movl    $.LC0, %eax
        movl    28(%esp), %edx
        movl    %edx, 8(%esp)
        movl    24(%esp), %edx
        movl    %edx, 4(%esp)
        movl    %eax, (%esp)
        call    printf
        addl    $1, 24(%esp)
.L2:
        cmpl    $9, 24(%esp)
        jle     .L3
        movl    $0, %eax
        leave
        ret
        .size   main, .-main
        .ident  "GCC: (GNU) 4.4.6 20110731 (Red Hat 4.4.6-3)"
        .section        .note.GNU-stack,"",@progbits

检查上述陈述

movl    28(%esp), %eax
movl    %eax, 24(%esp)

现在是最后一个例子t3.c

#include <stdio.h>

int main(void)
{
    int i;
    int u;

    for (i = 0; i < 10; i++) {
        i = u;
        printf("i = %d, u = %zu\n", i, u);
    }
    return 0;
}

以及随后的集会

        .file   "t3.c"
        .section        .rodata
.LC0:
        .string "i = %d, u = %zu\n"
        .text
.globl main
        .type   main, @function
main:
        pushl   %ebp
        movl    %esp, %ebp
        andl    $-16, %esp
        subl    $32, %esp
        movl    $0, 24(%esp)
        jmp     .L2
.L3:
        movl    28(%esp), %eax
        movl    %eax, 24(%esp)
        movl    $.LC0, %eax
        movl    28(%esp), %edx
        movl    %edx, 8(%esp)
        movl    24(%esp), %edx
        movl    %edx, 4(%esp)
        movl    %eax, (%esp)
        call    printf
        addl    $1, 24(%esp)
.L2:
        cmpl    $9, 24(%esp)
        jle     .L3
        movl    $0, %eax
        leave
        ret
        .size   main, .-main
        .ident  "GCC: (GNU) 4.4.6 20110731 (Red Hat 4.4.6-3)"
        .section        .note.GNU-stack,"",@progbits

现在你可以观察t2和t3,看看这里的区别,但是从拱到拱的确不同