程序很简单
//将一个字符数组逆序输出
#include <stdio.h>
#include <string.h>
int main()
{
char a[10] = "abcdefg";
for (int i = strlen(a) - 1; i >= 0; i--)
{
printf("%c", a[i]);
}
return 0;
}
有人觉得需要将"循环代码外提”,避免重复执行strlen(a) - 1,从而提高程序运行效率,像下面这样。没错,CSAPP和编译原理都是这么说的。
#include <stdio.h>
#include <string.h>
int main()
{
char a[10] = "abcdefg";
int i = strlen(a) - 1;
for (; i >= 0; i--)
{
printf("%c", a[i]);
}
return 0;
}
为了验证程序执行速度是不是真的提高了,重复执行一亿次。
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
int main()
{
clock_t t1 = clock();
char s[10] = "abcdefg";
int x = 0;
for (int n = 0; n < 100000000; n++)
{
for (int i = strlen(s) - 1; i >= 0; i--)
{
//printf("%c", s[i]);
x = x + i;
}
}
clock_t t2 = clock();
cout << t2 - t1 << "毫秒" << endl;
return 0;
}
为什么将printf语句注释掉了呢?输出是比较耗费时间的,为了测量程序真正的运行时间,IO语句要注释掉,加一条别的语句 x = x + i。运行结果如下:
C语言不愧是宇宙最快的语言之一,为了表示谦虚,加上“之一”二字。居然0毫秒就执行完了-_- 感觉不对啊,1亿好歹也是10的8次方呢?怎么0毫秒就完事了?要不把1亿次改成100亿试试? 不出意外的话,还是0毫秒。
看看汇编代码:
根本不见1亿的踪影?编译器的优化确实厉害,直接删除无效的代码,如果程序中的某些语句对输出没有影响,那么这些语句被视为无效代码 ,不执行。下面的代码加上一条输出x的语句,那么上述循环体的无效代码将变为有效代码。
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
int main()
{
clock_t t1 = clock();
char s[10] = "abcdefg";
int x = 0;
for (int n = 0; n < 100000000; n++)
{
for (int i = strlen(s) - 1; i >= 0; i--)
{
//printf("%c", s[i]);
x = x + i;
}
}
printf("%d\n", x); //增加一条输出语句
clock_t t2 = clock();
cout << t2 - t1 << "毫秒" << endl;
return 0;
}
运行结果如下:
执行时间大概是0.1秒多,相当于10^8(10的8次方)纳秒,for循环体循环次数刚好也是10^8,掐指一算,每次循环的平均执行时间是1纳秒,仅仅相当于从L1 cache取一次数据的时间,C语言叠加宇宙第一IDE优化的BUF,果然快的离谱。
编译器优化代码的权限很大,大到可以删除无效代码、更改代码执行次序。“只要保证对最后的输出结果没有影响”。如果是编写多线程代码,编译器也能随意更改单个线程里的代码执行次序,噩梦^_^
再看看汇编代码,这次看到了一亿的身影。
说了半天,循环代码还没外提呢,外提之后,试试运行速度会不会加快?
大失所望,运行速度并没有加快,再次感谢编译器的优化(在宇宙第一IDE里写代码,随便写,很难写出执行效率很低的代码)。计算密集型的程序,程序代码全部搞定之后,运行时记得把工具栏下拉框里的debug改成release,有惊喜^_^