一個有趣的計(jì)算機(jī)系統(tǒng)問題---判斷棧的增長方向
最近,我在某技術(shù)論壇上看到一個有趣的問題:如何判斷計(jì)算機(jī)系統(tǒng)中棧的增長方向?
首先讓我簡單介紹一下這個問題的背景。對于棧這種數(shù)據(jù)結(jié)構(gòu),大家應(yīng)該不會陌生,它是一種后進(jìn)先出的數(shù)據(jù)結(jié)構(gòu)。據(jù)說,在一般的計(jì)算機(jī)系統(tǒng)中,棧存在著兩種存放數(shù)據(jù)的方式,一種是向上增長的,一種是向下增長的,如圖1所示。
圖1 棧的兩種增長方向
在圖1的(a)中,棧是向上增長的,即數(shù)據(jù)A對應(yīng)的地址小于數(shù)據(jù)B對應(yīng)的地址;在圖1的(b)中,棧是向下增長的,即數(shù)據(jù)A對應(yīng)的地址大于數(shù)據(jù)B對應(yīng)的地址。那么,我們怎樣來判斷自己所使用的系統(tǒng)中的棧的增長方向到底屬于哪一種呢?
我們知道,作為一種常用的數(shù)據(jù)結(jié)構(gòu),棧主要用于存放程序中的局部變量和函數(shù)的輸入?yún)?shù)。那么,我們就可以設(shè)計(jì)一個程序,在程序中通過比較某一個局部變量的前后兩次的地址值來判斷棧的增長方向。利用這個想法編寫出來的程序如下所示:
- /**********************************************************************
- * 版權(quán)所有 (C)2017, Zhou Zhaoxiong。
- *
- * 文件名稱:FindStackDirection.c
- * 文件標(biāo)識:無
- * 內(nèi)容摘要:判斷棧的增長方向
- * 其它說明:無
- * 當(dāng)前版本:V1.0
- * 作 者:Zhou Zhaoxiong
- * 完成日期:20170630
- *
- **********************************************************************/
- #include <stdio.h>
- // 函數(shù)聲明
- void FindStackDirection(void);
- /**********************************************************************
- * 功能描述:主函數(shù)
- * 輸入?yún)?shù):無
- * 輸出參數(shù):無
- * 返 回 值:無
- * 其它說明:無
- * 修改日期 版本號 修改人 修改內(nèi)容
- * ---------------------------------------------------------------------------
- * 20170630 V1.0 Zhou Zhaoxiong 創(chuàng)建
- ***********************************************************************/
- int main()
- {
- FindStackDirection();
- return 0;
- }
- /**********************************************************************
- * 功能描述:查找棧增長方向
- * 輸入?yún)?shù):無
- * 輸出參數(shù):無
- * 返 回 值:無
- * 其它說明:無
- * 修改日期 版本號 修改人 修改內(nèi)容
- * --------------------------------------------------------------------------------
- * 20170630 V1.0 Zhou Zhaoxiong 創(chuàng)建
- ***********************************************************************/
- void FindStackDirection(void)
- {
- char iStackAddr = 0; // 用于獲取棧地址
- static char *pStackAddr = NULL; // 用于存放***個iStackAddr的地址
- if (pStackAddr == NULL) // ***次進(jìn)入
- {
- pStackAddr = &iStackAddr; // 保存iStackAddr的地址
- FindStackDirection(); // 遞歸
- }
- else // 第二次進(jìn)入
- {
- if (&iStackAddr > pStackAddr) // 第二次iStackDirection的地址大于***次iStackDirection, 那么說明棧增長方向是向上的
- {
- printf("Stack grows up!\n");
- }
- else if (&iStackAddr < pStackAddr) // 第二次iStackDirection的地址小于***次iStackDirection, 那么說明棧增長方向是向下的
- {
- printf("Stack grows down!\n");
- }
- else
- {
- printf("Bad stack!\n");
- }
- }
- }
我們可以看到,函數(shù)FindStackDirection中出現(xiàn)了遞歸調(diào)用,即***進(jìn)入該函數(shù)的時候,將iStackAddr變量(局部變量)的地址值賦給pStackAddr,第二次進(jìn)入該函數(shù)的時候,用新的iStackAddr變量的地址值與***次進(jìn)入該函數(shù)時iStackAddr變量的地址值相比較,如果前者大于后者,那么說明棧增長方向是向上的,否則,說明棧增長方向是向下的。
將以上代碼上傳到Linux機(jī)器上,使用“gcc -g -o FindStackDirection FindStackDirection.c”命令對程序進(jìn)行編譯之后,運(yùn)行“FindStackDirection”命令,結(jié)果如下:
- Stack grows down!
即我所使用的系統(tǒng)中的棧的增長方向是向下的。大家也可以將以上代碼在自己的系統(tǒng)中運(yùn)行一下,看看結(jié)果是什么。
在大部分人(包括我)的印象中,棧的增長方向只有一種,那就是向上(如圖1中的(a)),但程序運(yùn)行出來的結(jié)果與我們預(yù)期的恰恰相反。從這點(diǎn)也可以看出計(jì)算機(jī)系統(tǒng)在設(shè)計(jì)上的精妙與復(fù)雜,里面有很多東西都值得我們細(xì)細(xì)研究的。
【本文是51CTO專欄作者周兆熊的原創(chuàng)文章,作者微信公眾號:周氏邏輯(logiczhou)】