C语言代码执行顺序

说明:这里说的是代码执行顺序,不是c文件的预处理、编译、链接、执行…

1 问题起因

1、上学时,就有问过老师代码执行顺序,老师只是说不要想当然代码执行顺序,并未详细解释。
2、工作了还真遇到这个问题,搞了我两天才找到原因…

2 简单问题引入

先上一段简单代码。


#include<stdio.h>
int main(){
	int i=10;
	printf("%d %d %d\n",i++,i++,i++);
	
	i=10;
	printf("%d %d %d\n",++i,++i,++i);
	return 0;
}

大部分的编译器在数据入栈时都是从右向左执行,
先别看执行结果,按自己的认知写下执行结果。

10 11 12
11 12 13

我猜大部分人已经写下了这样的执行结果。
下面来编译执行一下来看看:在这里插入图片描述
对的你没看错,和你想的不一样。

这是为什么呢?肯定和编译器有关系啊。那就是汇编文件有关,生成一个汇编文件打开来看看。

[root@hezaizai test]# gcc -S execute.c
[root@hezaizai test]# vim execute.s

在这里插入图片描述
有点不太方便查看,更好的办法是生成目标文件通过反汇编打开。

[root@hezaizai test]# gcc -c execute.c -o execute.o
[root@hezaizai test]# objdump -d execute.o
Disassembly of section .text:
0000000000000000 <main>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   48 83 ec 10             sub    $0x10,%rsp
   8:   c7 45 fc 0a 00 00 00    movl   $0xa,-0x4(%rbp)
   f:   8b 4d fc                mov    -0x4(%rbp),%ecx
  12:   8d 41 01                lea    0x1(%rcx),%eax
  15:   89 45 fc                mov    %eax,-0x4(%rbp)
  18:   8b 55 fc                mov    -0x4(%rbp),%edx
  1b:   8d 42 01                lea    0x1(%rdx),%eax
  1e:   89 45 fc                mov    %eax,-0x4(%rbp)
  21:   8b 45 fc                mov    -0x4(%rbp),%eax
  24:   8d 70 01                lea    0x1(%rax),%esi
  27:   89 75 fc                mov    %esi,-0x4(%rbp)
  2a:   89 c6                   mov    %eax,%esi
  2c:   bf 00 00 00 00          mov    $0x0,%edi
  31:   b8 00 00 00 00          mov    $0x0,%eax
  36:   e8 00 00 00 00          callq  3b <main+0x3b>
  3b:   c7 45 fc 0a 00 00 00    movl   $0xa,-0x4(%rbp)
  42:   83 45 fc 01             addl   $0x1,-0x4(%rbp)
  46:   83 45 fc 01             addl   $0x1,-0x4(%rbp)
  4a:   83 45 fc 01             addl   $0x1,-0x4(%rbp)
  4e:   8b 4d fc                mov    -0x4(%rbp),%ecx
  51:   8b 55 fc                mov    -0x4(%rbp),%edx
  54:   8b 45 fc                mov    -0x4(%rbp),%eax
  57:   89 c6                   mov    %eax,%esi
  59:   bf 00 00 00 00          mov    $0x0,%edi
  5e:   b8 00 00 00 00          mov    $0x0,%eax
  63:   e8 00 00 00 00          callq  68 <main+0x68>
  68:   b8 00 00 00 00          mov    $0x0,%eax
  6d:   c9                      leaveq
  6e:   c3                      retq

在这里简单解释些要点,更多汇编语言自行学习。

++i对应的是: addl $0x1,-0x4(%rbp)
也就是直接执行a+1;

i++对应的是: mov -0x4(%rbp),%ecx
lea 0x1(%rax),%esi
入栈对应:mov 0x1c(%esp), %edx

总结下:

  • 在将参数入栈前,编译器会先把参数的的表达式都处理掉,哪怕这些运算会改变其中某些参数的值
  • 对于a++操作,编译器会开辟一个缓冲区来保存当前a的值,然后再对a操作,取值时是从缓冲区取,而不是直接从a的内存地址里取。

3 实际问题解决

源代码:

static void skipSpace(char **v_strptr)
{
    while ((** v_strptr>=0) &&(** v_strptr < _ctype_len) && isspace ( ** v_strptr))
    	++ * v_strptr;
	if(** v_strptr >= _ctype_len)
	{
		* v_strptr =NULL;
	}
}

修改后:

static void skipSpace(char **v_strptr)
{
	char *temp = *v_strptr;
	char *p = *v_strptr;
	size_t len = strlen(temp) - 1;
	while ((*v_strptr < temp + len) && (*p >= 0) && (*p < _ctype_len) && isspace (*p)){
		++ *v_strptr;
		++ p;
	}
	if(** v_strptr >= _ctype_len)
	{
		* v_strptr =NULL;
	}
}

参考:http://www.cnblogs.com/easonliu/p/4224120.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值