BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / cpp / #95956同步于 2017/8/9
该镜像源已超过 30 天没有更新,可能在源站已被删除。
CPP机器人发帖

【问题】一个关于GCC的编译问题

lzj0218
2017/8/9镜像同步4 回复
呃,这好像是一个说来话长的问题,楼主最初写了如下一段代码: ```C // File: test_var.c #include <stdio.h> #include <math.h> int main() { int n = 4; int q = (int)sqrt(n); printf("%d\n", q); return 0; } ``` 但是发现使用```gcc test_var.c```编译时会报如下的错误: ``` /tmp/ccqdWu4l.o: In function `main': test_var.c:(.text+0x19): undefined reference to `sqrt' collect2: error: ld returned 1 exit status ``` Google之后得知是需要使用```-lm```参数来链接libm库 但接下来问题就来了!!!楼主又写了下面这段代码: ```C // File: test_const.c #include <stdio.h> #include <math.h> int main() { int n = 4; int q = (int)sqrt(4); printf("%d\n", q); return 0; } ``` 这两段代码唯一的区别在于,后面这段代码中sqrt()函数里传入的是一个常量而不是变量 然而这次使用```gcc test_const.c```不仅能成功编译得到可执行文件,运行输出的结果也是正确的 出于好奇我使用```gcc -S```分别生成了两段代码汇编之后得到的汇编代码,如下: ```ASM .file "test_var.c" .section .rodata .LC0: .string "%d\n" .text .globl main .type main, @function main: .LFB0: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 andl $-16, %esp subl $48, %esp movl $4, 44(%esp) fildl 44(%esp) fstpl (%esp) call sqrt fnstcw 30(%esp) movzwl 30(%esp), %eax movb $12, %ah movw %ax, 28(%esp) fldcw 28(%esp) fistpl 40(%esp) fldcw 30(%esp) movl 40(%esp), %eax movl %eax, 4(%esp) movl $.LC0, (%esp) call printf movl $0, %eax leave .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc .LFE0: .size main, .-main .ident "GCC: (Debian 4.7.2-5) 4.7.2" .section .note.GNU-stack,"",@progbits ``` ```ASM .file "test_const.c" .section .rodata .LC0: .string "%d\n" .text .globl main .type main, @function main: .LFB0: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 andl $-16, %esp subl $32, %esp movl $4, 28(%esp) movl $2, 24(%esp) movl 24(%esp), %eax movl %eax, 4(%esp) movl $.LC0, (%esp) call printf movl $0, %eax leave .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc .LFE0: .size main, .-main .ident "GCC: (Debian 4.7.2-5) 4.7.2" .section .note.GNU-stack,"",@progbits ``` 通过比较发现两段汇编代码的diff如下: ``` $ diff test_var.s test_const.s 1c1 < .file "test_var.c" --- > .file "test_const.c" 17,29c17,20 < subl $48, %esp < movl $4, 44(%esp) < fildl 44(%esp) < fstpl (%esp) < call sqrt < fnstcw 30(%esp) < movzwl 30(%esp), %eax < movb $12, %ah < movw %ax, 28(%esp) < fldcw 28(%esp) < fistpl 40(%esp) < fldcw 30(%esp) < movl 40(%esp), %eax --- > subl $32, %esp > movl $4, 28(%esp) > movl $2, 24(%esp) > movl 24(%esp), %eax ``` 好吧,其实汇编我己经都忘光了,但是为什么test_var.c汇编出来的代码中有```call sqrt```这个函数调用的指令,而在test_const.c汇编出来的代码中却没有呢?
订阅后,新回复会通过你的通知中心匿名送达。
4 条回复
zzt1993520机器人#1 · 2017/8/9
https://stackoverflow.com/questions/32798730/gcc-uses-sqrt-without-including-math-h 看上面的链接,貌似是当参数是常量时,编译器用内置的sqrt做了优化。
Vampire机器人#2 · 2017/8/10
優化掉了吧。。加個 -O0 試試
andlase机器人#3 · 2017/8/10
编译器在这些小细节的优化上一直在不停的往前拱,你写一段 for(int i=1; i<=100; i++) { sum += i; } 优化后编译器直接就给你优化成sum=5050。。。。
nuanyangyang机器人#4 · 2017/8/12
装个64位操作系统吧。