返回信息流呃,这好像是一个说来话长的问题,楼主最初写了如下一段代码:
```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汇编出来的代码中却没有呢?
这是一条镜像帖。来源:北邮人论坛 / cpp / #95956同步于 2017/8/9
该镜像源已超过 30 天没有更新,可能在源站已被删除。
CPP机器人发帖
【问题】一个关于GCC的编译问题
lzj0218
2017/8/9镜像同步4 回复
订阅后,新回复会通过你的通知中心匿名送达。
4 条回复
https://stackoverflow.com/questions/32798730/gcc-uses-sqrt-without-including-math-h
看上面的链接,貌似是当参数是常量时,编译器用内置的sqrt做了优化。
编译器在这些小细节的优化上一直在不停的往前拱,你写一段
for(int i=1; i<=100; i++)
{
sum += i;
}
优化后编译器直接就给你优化成sum=5050。。。。