使用字符串文字

时间:2018-12-21 08:52:03

标签: c gcc assembly arm array-initialization

根据this thread,使用较短的字符串文字初始化数组会用零填充该数组。

那么,为ARM Cortex M4编译时,这两个函数(test1test2)为什么会产生不同的结果?

extern void write(char * buff);

void test1(void)
{
    char buff[8] = {'t', 'e', 's', 't', 0, 0, 0, 0 };
    write(buff);
}

void test2(void)
{
    char buff[8] = "test";
    write(buff);
}

我得到equivalent assemblies for x86-64,但是在ARM gcc上我得到different output

test1:
        str     lr, [sp, #-4]!
        sub     sp, sp, #12
        mov     r3, sp
        ldr     r2, .L4
        ldm     r2, {r0, r1}
        stm     r3, {r0, r1}
        mov     r0, r3
        bl      write
        add     sp, sp, #12
        ldr     pc, [sp], #4
.L4:
        .word   .LANCHOR0
test2:
        mov     r3, #0
        str     lr, [sp, #-4]!
        ldr     r2, .L8
        sub     sp, sp, #12
        ldm     r2, {r0, r1}
        str     r0, [sp]
        mov     r0, sp
        strb    r1, [sp, #4]
        strb    r3, [sp, #5]
        strb    r3, [sp, #6]
        strb    r3, [sp, #7]
        bl      write
        add     sp, sp, #12
        ldr     pc, [sp], #4
.L8:
        .word   .LANCHOR0+8

1 个答案:

答案 0 :(得分:3)

首先,在构成名为buf的对象的内存内容相同的意义上,该代码是等效的。

也就是说,编译器显然会为第二个函数生成更差的代码。因此,由于存在一种产生具有等效语义的更优化代码的方法,因此可以合理地将其视为编译器中的优化失败并为其提交错误。

如果编译器希望发出相同的代码,则必须认识到可以在不更改程序语义的情况下对内存中的字符串文字表示进行零填充(尽管不能对字符串文字进行填充,因为{{ 1}}不能等于sizeof "test")。

但是,因为如果字符串文字用于初始化比文字长的且不包含普通字符串语义的显式长度数组(通常是个坏主意),则这仅会是有利的。足够(比空终止符大一些的字节是相关的),这种情况下进行更好的优化的价值似乎有限。

附录:如果将Godbolt设置为不删除汇编程序指令,则可以看到如何创建文字:

sizeof "test\0\0\0"

有趣的是,编译器不会进行重复数据删除,而是将字符串文字后的填充留给汇编器(.section .rodata .align 2 .set .LANCHOR0,. + 0 .byte 116 .byte 101 .byte 115 .byte 116 .byte 0 .byte 0 .byte 0 .byte 0 .ascii "test\000" .space 3 ),而不是将其显式清零。