C和汇编(你想知道的C语言 3.6)

C语言其实是个绝世高手,它一直隐藏"汇编“的身份,别人以为汇编是汇编,C语言只是默默一笑: 汇编只是我的代理人。

 

Q: 选择语句if是如何对应汇编的?

A: 

int i;
int j;

if (i == 1)
	j = 0;
else
	j = 1;
0000000100000f92	cmpl	$0x1, -0x14(%rbp)   // i == 1 ?
0000000100000f96	jne	0x100000fa8
0000000100000f9c	movl	$0x0, -0x18(%rbp)   // j = 0
0000000100000fa3	jmp	0x100000faf
0000000100000fa8	movl	$0x1, -0x18(%rbp)   // j = 1
0000000100000faf	xorl	%eax, %eax

    判断i是否为1:   cmpl指令判断相等;  jne代表不为0跳转(cmp为减运算);  jmp为无条件跳转,此处为i == 1的情况。

 

Q: for循环是如何对应汇编的?

A: 

 int i;
 int j;

 for(i = 1; i < 10; ++i)
     j = i;
0000000100000f82	movl	$0x1, -0x14(%rbp)    // i = 1
0000000100000f89	cmpl	$0xa, -0x14(%rbp)    // i < 10
0000000100000f8d	jge	0x100000fa7          // when i >= 10, jump out
0000000100000f93	movl	-0x14(%rbp), %eax    // now, i < 10
0000000100000f96	movl	%eax, -0x18(%rbp)    // j = i
0000000100000f99	movl	-0x14(%rbp), %eax
0000000100000f9c	addl	$0x1, %eax            // ++i
0000000100000f9f	movl	%eax, -0x14(%rbp)
0000000100000fa2	jmp	0x100000f89
0000000100000fa7	xorl	%eax, %eax

  对于for循环,比较和跳转指令实现初始化和判断跳转功能。

 

Q: while循环如何对应汇编?

A: 

int i = 1;
int j;

while(i < 10) {
    j = i;
    ++i;
}
0000000100000f82	movl	$0x1, -0x14(%rbp)    // i = 1
0000000100000f89	cmpl	$0xa, -0x14(%rbp)    // i >= 10 ?
0000000100000f8d	jge	0x100000fa7          // jump out     
0000000100000f93	movl	-0x14(%rbp), %eax    
0000000100000f96	movl	%eax, -0x18(%rbp)    // j = i
0000000100000f99	movl	-0x14(%rbp), %eax
0000000100000f9c	addl	$0x1, %eax           // ++i
0000000100000f9f	movl	%eax, -0x14(%rbp)
0000000100000fa2	jmp	0x100000f89
0000000100000fa7	xorl	%eax, %eax

    while和if语句很相近,因为它们表达的含义是相近的。

 

Q: break对应汇编是什么?

A: 

int i = 1;
int j;

while(i < 10) {
    if (i > 5)
        break;

    j = i;
    ++i;
}

0000000100000f72	movl	$0x1, -0x14(%rbp)
0000000100000f79	cmpl	$0xa, -0x14(%rbp)
0000000100000f7d	jge	0x100000fa6
0000000100000f83	cmpl	$0x5, -0x14(%rbp)      // i > 5 ?
0000000100000f87	jle	0x100000f92            // i <= 5, continue
0000000100000f8d	jmp	0x100000fa6            // i > 5, jump out
0000000100000f92	movl	-0x14(%rbp), %eax
0000000100000f95	movl	%eax, -0x18(%rbp)
0000000100000f98	movl	-0x14(%rbp), %eax
0000000100000f9b	addl	$0x1, %eax
0000000100000f9e	movl	%eax, -0x14(%rbp)
0000000100000fa1	jmp	0x100000f79
0000000100000fa6	xorl	%eax, %eax

   break实际也只是比较和跳转指令的代名词,continue也是类似就不再赘述。

 

Q: switch/case语句如何对应汇编?

A: 

int i;    // not initialize it on purpose
int j;

switch(i) {
    case 1:
        j = 1;
        break;
    case 2:
        j = 2;
        break;
    default:
        j = 0;
        break;
}
0000000100000f62	movl	-0x14(%rbp), %edi
0000000100000f65	movl	%edi, %eax           // i is in %eax
0000000100000f67	subl	$0x1, %eax           // i == 1?
0000000100000f6a	movl	%edi, -0x1c(%rbp)
0000000100000f6d	movl	%eax, -0x20(%rbp)
0000000100000f70	je	0x100000f8f          // case 1
0000000100000f76	jmp	0x100000f7b
0000000100000f7b	movl	-0x1c(%rbp), %eax
0000000100000f7e	subl	$0x2, %eax           // i == 2?
0000000100000f81	movl	%eax, -0x24(%rbp)
0000000100000f84	je	0x100000f9b          // case 2
0000000100000f8a	jmp	0x100000fa7
0000000100000f8f	movl	$0x1, -0x18(%rbp)    // case 1: j = 1
0000000100000f96	jmp	0x100000fae
0000000100000f9b	movl	$0x2, -0x18(%rbp)    // case 2: j = 2
0000000100000fa2	jmp	0x100000fae
0000000100000fa7	movl	$0x0, -0x18(%rbp)    // default: j = 0
0000000100000fae	xorl	%eax, %eax

  又是一堆比较和跳转指令,不过综上所述,好像也没有多少指令就表达了C语言大部分语法概念。

 

  C语言和汇编其实很近,可参考:汇编和c只有一步之近----小话c语言(19)

  在计算机性能越来越高的情况下,坚持用汇编也许会稍许提升性能,但很可能已无实在意义,只有纯技术讨论的意义。当然,万物都有局限,当C语言真的没办法直接表达,转用汇编解决问题才是真正吃透了C语言.

 

作者:     陈曦
环境:     MacOS 10.14.5 (Intel i5)
         Apple LLVM version 10.0.1 (clang-1001.0.46.4)
         Target: x86_64-apple-darwin18.6.0
 
         Linux 3.16.83 (Ubuntu)
 
转载请注明出处

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值