c - 使用字符串文字初始化数组时的不同程序集

标签 c gcc assembly arm array-initialization

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

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

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

最佳答案

首先,代码是等效的,因为构成名为 buf 的对象的内存内容是相同的。

也就是说,编译器显然会为第二个函数生成更糟糕的代码。因此,由于有一种方法可以生成具有等效语义的更优化的代码,因此有理由认为这是编译器中的优化失败并为此提交错误。

如果编译器想要发出相同的代码,它必须认识到可以在不改变程序语义的情况下对内存中的字符串文字表示进行零填充(尽管字符串文字本身不能被填充,因为 sizeof "test" 不能等于 sizeof "test\0\0\0")。

但是,因为这只有是有利的,如果字符串文字用于初始化比文字更长的显式长度数组(通常是一个坏主意)并且正常字符串语义不是足够(空终止符之后的字节是相关的),对这种情况进行更好优化的值(value)似乎有限。

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

.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

有趣的是,编译器不进行重复数据删除,而是将字符串文字后的填充留给汇编程序 (.space 3),而不是显式将其置零。

关于c - 使用字符串文字初始化数组时的不同程序集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53881708/

相关文章:

c++ - 在 Visual C++ 中接受来自客户端(套接字编程)的连接的问题

将二进制数转换为十六进制的 C 程序无法转换两个以上的二进制数(如果它们等于十六进制字母)

c - 指向 C 中的结构 - 错误 : expected ')' before '*' token

gcc - 为什么链接库的顺序有时会导致 GCC 出错?

c++ - RDTSCP 和指令顺序

c - 具有最小内存占用的程序(在 Linux 上)

c++ - 正确处理字节对齐问题 -- 16位嵌入式系统和32位桌面通过UDP

c - 尝试在 Mac OSX 上设置 clang 和 llvm 以使用 gedit 运行 runC

c++ - 异步与 Visual Studio 2013(Windows8.1) 和 GCC 4.9(Ubuntu14.10) 的不同行为

assembly - 为什么组装后的可执行文件大小相同