在Linux下工作,我刚刚遇到了以下问题。 (当然,有人会给我答案,但到目前为止,我没有找到任何简单明了的答案:)
/*compile with gcc -o out.x hello.c*/
#include<stdio.h>
int main()
{
printf("Hello World2\r\n");
printf("Hello World3\r\n ");
return 0;
}
在Linux下运行以下代码给出两个字符串但结尾字符是不同的:第一个输出以0x0d结尾,而第二个以0x0d,0x0a结尾。
这是由编译器(GCC)完成的,如obj文件中所示:
Contents of section .rodata:
400610 01000200 48656c6c 6f20576f 726c6432 ....Hello World2
400620 0d004865 6c6c6f20 576f726c 64330d0a ..Hello World3..
400630 2000 .
所以,问题是:
谢谢
ask GCC(在Linux / Debian / Sid / x86-64上使用GCC7.2)发出汇编程序更简单。所以我编写了你的程序bflash.c
gcc -fverbose-asm -O0 -S bflash.c -o bflash-O0.S
没有优化就可以得到它
gcc -fverbose-asm -O1 -S bflash.c -o bflash-O1.S
获得-O1
优化。随意用各种other optimization flags重复实验。
即使没有优化,bflash-O0.S
包含:
.section .rodata
.LC0:
.string "Hello World2\r"
.LC1:
.string "Hello World3\r\n "
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp #
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp #,
.cfi_def_cfa_register 6
# bflash.c:5: printf("Hello World2\r\n");
leaq .LC0(%rip), %rdi #,
call puts@PLT #
# bflash.c:6: printf("Hello World3\r\n ");
leaq .LC1(%rip), %rdi #,
movl $0, %eax #,
call printf@PLT #
# bflash.c:8: return 0;
movl $0, %eax #, _4
# bflash.c:9: }
popq %rbp #
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
如你所见,第一个printf
已被优化为puts
;这是C11标准n1570(as-if rule)允许的。顺便说一句,bflash-01.S
包含类似的代码。请注意,C11标准已经考虑了当前的优化实践(标准化委员会的许多成员都是编译器实现者)。
BTW Clang 5,作为clang-5.0 -O1 -fverbose-asm -S bflash.c -o bflash-01clang.s
调用,执行相同类型的优化。
我怎样才能避免这种“优化”(!?)
关注Daniel H's answer(你可以编译with -ffreestanding
,但我不建议这样做)。
或者避免使用printf
中的<stdio.h>
并实现自己的慢速打印功能。如果您实现自己的打印功能,请以不同的名称命名(因为printf
是在C11标准中定义的),也许(如果需要的话)编写您自己的GCC plugin以便按照您的方式进行优化(并且该插件最好是一些免费软件is GPL compatible ,阅读GCC runtime library exception)。
C语言规范(研究n1570)定义了semantics,即编译程序的行为。它不需要任何特定的字节序列出现在可执行文件中(标准中甚至可能没有提到)。如果你需要这样的属性,找到一种不同的编程语言,并放弃所有重要的optimizations GCC正在努力为你做。优化正在制作writing a C compiler difficult(如果你想要一个非优化的编译器,使用GCC以外的其他东西,但接受在性能方面可能损失三倍或更多,w.r.t。使用gcc -O2
编译的代码)。