最近因为在准备面试,所以看了不少面试题。每个都仔细分析,争取不留死角并解决自己的所有疑惑,同时也提高编程水平。今天偶然发现对for循环语句的头部执行顺序还有一点小疑惑,虽然经常使用,但往往不太关注某些具体细节。因为是搞嵌入式的,所以对底层细节还是熟悉一点比较好。通过在网上查阅资料发现不少对此知识点的解读,但往往仅就C语言本身进行讲解,没有解释底层实现情况。大学期间学过微机原理,所以对汇编语言也有些了解,前不久在CSDN上看了赵中老师的“C语言指针与汇编内存地址”,最近对汇编级的调试挺感兴趣,所以今天我准备就for循环语句的汇编级实现进行介绍。
以下程序编写调试的开发环境为Microsoft Visual Studio Professional 2015,所有结果及结论仅适用于本开发环境,其它开发环境的实现情况未亲自测试,在此不做评价。首先编写了一个C语言小程序如下:
#include<stdio.h>
char i;
int main()
{
for (i = 0; i < 2; i++)
{
printf("hello world\n");
}
}
最初我所理解的执行顺序是:i=0赋值 → 打印输出 → i++ → i<2进行判断 → 打印输出 → i++ → i<2进行判断 → 打印输出 → i++ → ......(红色为一个循环)这样最终执行两次输出,与程序运行输出结果一致。但在反汇编中却发现并不是这样运行的。按F11进行单步调试发现执行顺序如下图,图中printf函数一步跳过执行:
汇编指令的解释在此不做过多介绍。由图可知,首先执行“ mov byte ptr [i (0F58139h)], 0 ” 即给 i 赋值,i=0,然后程序跳转执行i<2判断语句,之后执行打印输出语句,接着执行i++操作,再进行i<2比较,接着打印输出......这样程序执行流程为: i=0赋值 → i<2进行判断 → 打印输出 → i++ →i<2进行判断 → 打印输出 → i++ → ......(红色为一个循环)这样最终也执行两次输出,与程序运行输出结果一致。可见我之前的理解是错误的,之所以运行结果一致仅仅是巧合,如果是 for (i = 0; i < 0; i++) 则执行结果不一致。只不过这种情况往往很少见到。综上所述,for循环语句的头部执行顺序为(至少在本开发环境中是这样的):
i 初始赋值 → 执行条件判断 → 打印输出等语句 → i 赋新值 → 执行条件判断 → 打印输出等语句 → i 赋新值 ......