CSAPP-Course Overview

Course Overview

數組下標越界訪存

#include <stdio.h>
typedef struct {
	int a[2];
	double d;
} struct_t;
double fun(int i) {
	volatile struct_t s;
	s.d = 3.14;
	s.a[i] = 1073741824;
	return s.d;
}
int main() {
	for (int i = 0; i < 100; ++i)
	{
		printf("fun(%d) = %.8lf\n", i, fun(i));
	}
	return 0;
}


fun(0) = 3.14000000
fun(1) = 3.14000000
fun(2) = 3.13999987
fun(3) = 2.00000061
fun(4) = 3.14000000
fun(5) = 3.14000000
zsh: segmentation fault

在這裏插入圖片描述
由於數組下標索引越界不檢查,當i >= 2時會修改a數組內存後的區域。當修改a[2],a[3]的時候會影響到結構體雙精度浮點數d的內存空間,從而影響fun函數的返回值。當i>=4時會繼續修改後面的內存,當i爲6時觸發了段錯誤導致程序崩潰,該內存最有可能是記錄已經分配的內存無法修改。

訪問內存方式與性能的關係

#include <stdio.h>
#include <time.h>
int a[2048][2048], b[2048][2048];
void copyij(int src[2048][2048], int dst[2048][2048])
{
	int i, j;
	for (i = 0; i < 2048; ++i)
	{
		for (j = 0; j < 2048; ++j)
		{
			dst[i][j] = src[i][j];
		}
	}
}
void copyji(int src[2048][2048], int dst[2048][2048])
{
	int i, j;
	for (j = 0; j < 2048; ++j)
	{
		for (i = 0; i < 2048; ++i)
		{
			dst[i][j] = src[i][j];
		}
	}
}
int main()
{
	clock_t start_time, end_time;
	double duration;

	start_time = clock();
	copyij(a, b);
	end_time = clock();
	duration = double(end_time - start_time) / CLOCKS_PER_SEC;
	printf("copyij的運行時間: %lf\n", duration);

	start_time = clock();
	copyji(a, b);
	end_time = clock();
	duration = double(end_time - start_time) / CLOCKS_PER_SEC;
	printf("copyji的運行時間: %lf", duration);
	return 0;
}

copyij的運行時間: 0.024819
copyji的運行時間: 0.112909

CLOCKS_PER_SEC是標準c的time.h頭函數中宏定義的一個常數,表示一秒鐘內CPU運行的時鐘週期數,用於將clock()函數的結果轉化爲以秒爲單位的量,但是這個量的具體值是與操作系統相關的。
在這裏插入圖片描述

在一臺普通個人臺式機上粗略計算可以看到copyij與copyji性能上的差距,特定的機器上,我們運行它的性能會有更大的差距。不同的訪存方式會有不同的性能體驗,很明顯得得出結論先行再列的訪問方式由於先列後行的方式。我的猜想是:dst[i][j]實質是指針訪問*((dst + i * 2048) + j)頻繁地移動回溯指針性能消耗大。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章