根据this thread,使用较短的字符串文字初始化数组会用零填充该数组。
那么,为ARM Cortex M4编译时,这两个函数(test1
和test2
)为什么会产生不同的结果?
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
答案 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
),而不是将其显式清零。