国产久操视频-国产久草视频-国产久热精品-国产久热香蕉在线观看-青青青青娱乐-青青青青在线成人视99

  • 正文
    • 如何踩坑的?
    • 事實(shí)真的一定如此嗎?
    • 預(yù)防及解決措施
  • 相關(guān)推薦
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

不小心踩了指針和內(nèi)存地址對(duì)齊的坑

04/26 08:25
1110
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

指針,是C語言中的一個(gè)重要概念及其特點(diǎn),也是掌握C語言比較困難的部分。指針也就是內(nèi)存地址,指針變量是用來存放內(nèi)存地址的變量。

本質(zhì)還是一個(gè)變量,指針提供了一種對(duì)存儲(chǔ)位置的動(dòng)態(tài)訪問手段,(相對(duì)于普通變量而言,普通變量只能訪問自己所占的存儲(chǔ)位置)

內(nèi)存地址對(duì)齊,是計(jì)算機(jī)在內(nèi)存中的數(shù)據(jù)排列、訪問數(shù)據(jù)的方式,包含了基本數(shù)據(jù)對(duì)齊和結(jié)構(gòu)體數(shù)據(jù)對(duì)齊的兩種相互獨(dú)立又相互關(guān)聯(lián)的部分。

現(xiàn)代計(jì)算機(jī)在內(nèi)存中讀寫數(shù)據(jù)是按字節(jié)塊進(jìn)行操作,理論上任意類型的變量訪問可以從任何地址開始,但是計(jì)算機(jī)系統(tǒng)對(duì)任意數(shù)據(jù)類型在內(nèi)存中存放位置有限,它會(huì)要求這些數(shù)據(jù)的首地址的值為K(4位或者8位)的整數(shù)倍。

如何踩坑的?

在一份十分優(yōu)秀的代碼中,指針的使用率占比很高,因?yàn)橹羔樐茏尨a實(shí)現(xiàn)變得更自由、更高效和更方便等諸多優(yōu)點(diǎn),可對(duì)于不十分熟悉指針的朋友來說,用起來也許就是災(zāi)難(常見的就是程序跑飛)

因此,通過指針的使用率大概就能判斷一個(gè)人的編程能力水平

請(qǐng)看下面的代碼,運(yùn)行結(jié)果是怎么樣的呢?

//?假設(shè)數(shù)組首地址為?0x00004000,符合內(nèi)存對(duì)齊:4的倍數(shù)
static?unsigned?char?sg_arrBuf[100];

int?main()
{
memset(sg_arrBuf,?0,?sizeof(sg_arrBuf));

//?地址為?0x00004000
uint8_t?*pucVal?=?(uint8_t?*)&sg_arrBuf[0];

//?地址為?0x00004001
uint16_t?*puiVal?=?(uint16_t?*)&sg_arrBuf[1];

*pucVal?=?20;???//?HEX:?0x14
*puiVal?=?2000;?//?HEX:?0x07d0

printf("HEX:?");

for?(int?i?=?0;?i?<?3;?i++)
{
printf("%02x?",?sg_arrBuf[i]);
}

printf("n");

return?0;
}

很多朋友期望的結(jié)果如下(小端模式):

HEX:?14?d0?07

事實(shí)真的一定如此嗎?

不一定!

也許部分朋友在自己電腦上打開 VS 復(fù)制粘貼運(yùn)行了,編譯后運(yùn)行,結(jié)果還真和上面一樣?。?!你這不是在忽悠人嗎?。?!

那有試過在 MCU 上跑過嗎?是不是程序跑飛了?

為什么?

當(dāng)計(jì)算機(jī)讀取或?qū)懭雰?nèi)存地址時(shí),它將以字(word)大小的塊進(jìn)行存儲(chǔ)。數(shù)據(jù)對(duì)齊意味著將數(shù)據(jù)放在等于字長(zhǎng)的倍數(shù)的內(nèi)存偏移處,正是由于這種CPU處理內(nèi)存的方式從而提高了系統(tǒng)的性能。大多數(shù)CPU只能訪問內(nèi)存對(duì)齊的地址。

意味著部分系統(tǒng)架構(gòu)體系對(duì)于未對(duì)齊的地址進(jìn)行訪問時(shí)會(huì)發(fā)生異常,如果嘗試去訪問內(nèi)存未對(duì)齊的變量進(jìn)行操作會(huì)導(dǎo)致總線錯(cuò)誤。它只支持對(duì)齊訪問。

比如我們?cè)L問一個(gè) 4 字節(jié) (Double Word) 型的變量時(shí),如果這個(gè)變量的起始地址是能被 4 整除的話,我們說這種訪問是雙字節(jié)對(duì)齊的。如果訪問一個(gè) 2 字節(jié) ( Word ) 變量,當(dāng)起始地址能被 2 整除時(shí)是對(duì)齊的。訪問字節(jié) ( Byte ) 型變量,總是對(duì)齊的。

根據(jù)這個(gè)就能很快鎖定問題原因了,那就是程序運(yùn)行到這個(gè)位置就導(dǎo)致總線錯(cuò)誤,從而跑飛了。

//?地址為?0x00004001,未對(duì)齊
*puiVal?=?2000;?//?HEX:?0x07d0

預(yù)防及解決措施

關(guān)于上述的寫法,有些朋友可能在電腦端實(shí)現(xiàn)了某個(gè)功能,電腦測(cè)試沒有任何問題,但是一旦移植到 MCU 上就不行,那么抓緊檢查一下是不是這個(gè)問題呢。

因此,為了確保我們的代碼有很高的移植性和穩(wěn)定性,那么一定要預(yù)防這種情況,可以通過采用訪問字節(jié) ( Byte ) 型變量,也可以使用memcpy的方式處理這種操作就能避免這種問題。

//?假設(shè)數(shù)組首地址為?0x00004000,符合內(nèi)存對(duì)齊: 4的倍數(shù)
static?unsigned?char?sg_arrBuf[100];

int?main()
{
memset(sg_arrBuf,?0,?sizeof(sg_arrBuf));

uint8_t?ucVal?=?20;
uint16_t?uiVal?=?2000;

memcpy(&sg_arrBuf[0],?&ucVal,?1);
memcpy(&sg_arrBuf[1],?&uiVal,?2);

printf("HEX:?");

for?(int?i?=?0;?i?<?3;?i++)
{
printf("%02x?",?sg_arrBuf[i]);
}

printf("n");

return?0;
}

相關(guān)推薦

延寿县| 凌云县| 喜德县| 新沂市| 威信县| 阿坝县| 通海县| 屯昌县| 射阳县| 即墨市| 隆化县| 麟游县| 兰坪| 荥阳市| 桂平市| 静乐县| 监利县| 苍南县| 岳池县| 定南县| 和平区| 册亨县| 雅安市| 榆社县| 阜城县| 仁怀市| 台前县| 宜都市| 疏勒县| 丹阳市| 东乡| 沁水县| 北辰区| 平定县| 敖汉旗| 民权县| 马龙县| 新巴尔虎左旗| 珲春市| 静海县| 象山县|