亚洲春色中文字幕久久久-三上亚,一吻二脱三床四吻胸,国产真实伦对白视频全集,在线毛片观看,精品成品入口黄网,国产毛aⅴ片久久久,亚洲AV色香蕉一区二区三区老师,萧皇后A级艳片,色情日本视频更新,99久久亚洲精品日本无码

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 7994|回復(fù): 1
打印 上一主題 下一主題
收起左側(cè)

STM32中*(int *)0x08001000寫法理解

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:90762 發(fā)表于 2018-10-22 23:05 | 只看該作者 |只看大圖 回帖獎勵 |倒序瀏覽 |閱讀模式
關(guān)于STM32中*(int*)0x08001000寫法理解

它與(*(volatile unsignedlong *)概念是一樣。請看51黑電子論壇嵌入式的C程序中(*(volatileunsigned long *)的理解文章。


注意:1.它與(int*)0x08001000 少了一*,是完全不同概念

2.在32位機正確,在16位機不一定正確。

*(int *)0x80001000 = 34; 與(int)0x80001000是等效


uint32GPIOx
說實在的,這個,和 那個顯得很麻煩的寫法
*(uint32_t*)&GPIOx
效果確實是一樣的。

在STM32上,可以通過
*(int *)0x08001000 = 34;
在地址為 0x80010000上寫入 34 這個內(nèi)容。

以下寫是理解,是一些其它論壇好文章。

——這里不考慮什么 FLASH RAM之類的問題。

所以,ST庫映射寄存器的典型手法就是
比如說 GPIOA的寄存器地址,如果是從 0x20001000開始存放什么 ODR IDR之類的。
因為 結(jié)構(gòu)體成員在內(nèi)存上也是按序排放的,所以,它就把
ODR IDR等等寄存器 按順序 定義成 GPIO 這個結(jié)構(gòu)體。
形如
typedef GPIO
{
    ODR;
    IDR;
};
這一部分具體可以去看stm32fxxx.h,我就不多說了。
最后,GPIOA GPIOBGPIOC都會有一個GPIOA_Base GPIOB_Base
這個基地址,指的就是 每個port端口寄存器的 起始地址。ABCDEFGI口各自按順序排好。
所以只要找到頭,再借助這個結(jié)構(gòu)體,就可以直接通過
GPIOA->ODR這樣的寫法非常簡單直觀的尋知道 GPIOA的ODR地址。
非常形象,非常生動。
而且很簡潔,完全的利用了C語法本身的特性。
是以,從我個人的角度看,這是一個非常不錯的 映射手法。
這基本也是那天晚上我語無倫次 發(fā)語音說的重點。
現(xiàn)在,先來回答原來那個帖子的問題。
*(uint32_t*)&GPIOx
這句話到底是什么意思?
其實問題還是在上一個帖子里提到的 GPIOx的定義里
#define GPIOA    ((GPIO_TypeDef*)GPIOA_BASE)
其實我為什么第一反應(yīng)會覺得這個東西寫的挺新鮮,因為以前我曾小小糾結(jié)過如何通過一個函數(shù),讓函數(shù)自己區(qū)分 GPIOA GPIOB這個問題。
而這里提供了一個 非常直接簡單的方法:

*(uint32_t*)&  GPIOx
對這種較復(fù)雜的表達式或者宏,解決的思路很簡單,就是一步一步展開。但這個過于簡單,而且這個話題也太口水了,我就直接帶過去不羅嗦了,羅嗦了你們還以為是我無知大驚小怪......(多怨啊我,我只是一個喜歡 詳細(xì)解釋的好版主)
GPIOx 是傳遞進來的形參,它的可能值就是 GPIOA GPIOB之類的
那也就是
((GPIO_TypeDef*GPIOA_BASE
GPIOA_BASE是一個數(shù)值,代表的是 GPIOA的寄存器的起始地址
*(uint32_t*)&GPIOx
這個操作,等于,把GPIOA_BASE 這個最初宏定義的數(shù)值,就是說,這是一個常數(shù)。
所以這個時候,就可以很方便的使用 switch-case結(jié)構(gòu)了
因為case后面跟的只能是常數(shù),而不能是變量或者其他任何數(shù)值。
這就是這個問題的所有答案
只是,我強調(diào) 后面這種寫法,我的理由在于:
可讀性。
看到前者,你不會聯(lián)想到 GPIOx是一個地址,而看到后者,稍微有點經(jīng)驗的C程序員都馬上會領(lǐng)悟到這一點。
這就很重要。
為什么,因為,在類似的環(huán)境下,我就會搞懵。
比如說,最開始主樓貼 的那個圖。
那是 人民幣君發(fā)的。
我一開始因為直接聯(lián)想到 這個放假前的討論,因此我想都沒想,就直接說,這兩個效果是一樣的。
然而,果真是一樣嗎?呵呵,那還真不是。
比如說

{
*(int *)0x80001000 = 34;
(int)0x80001000
while(1);
}
寫到這里,我就懵逼了,看出問題了沒?
一個是那個數(shù)其實是地址值,要去操作那個地址上的內(nèi)容
另一個,壓根就只是一個常數(shù)。
這兩個操作的出來的結(jié)果和影響完全不一樣。
-----------------------------------------------------------------------
首先來討論一個我認(rèn)為很有意思的問題,就是這兩個強制類型轉(zhuǎn)換:
*(uint32_t*)&AAA 是否等價于 (uint32_t)AAA ?(假設(shè)我們不知道AAA的類型,變量還是常量)

為了便于討論,我們假設(shè)變量uint32_tX=*(uint32_t*)&AAA, Y=(uint32_t)AAA;

乍一看,好像是有點等價的意思,但是仔細(xì)想想,又不是那么回事,這還取決于AAA的類型。
(1).現(xiàn)在假設(shè)AAA是2字節(jié)short型=0x1234;
那么X的結(jié)果是強制從AAA的地址中取走4字節(jié),其中2字節(jié)未知:
X=0xXXXX1234 (小端情況下)
Y的結(jié)果就比較確定,編譯器幫他把高位填0, Y=0x00001234;
(2).假設(shè)AAA是64位long long類型=0x1234;前面的0我就不寫了。
那么X還是取走4個字節(jié),根據(jù)大小端而異,可能是高4字節(jié),也可能是低四字節(jié)。
Y只是簡單的舍棄了高四字節(jié),結(jié)果比較確定。
(3). 假設(shè)AAA是個數(shù)組,這個情況比較特殊,數(shù)組名本身就是數(shù)組的首地址,取地址后還是相同的值:
因此X會取出數(shù)組中的元素
而Y卻還是一個地址值。
(4). 一個不靠譜的假設(shè)AAA是個結(jié)構(gòu)體
那么X可以取到結(jié)構(gòu)體的成員
而Y的寫法就直接報錯了,不允許強制類型轉(zhuǎn)換。
(5). AAA是uint32_t類型,那么沒什么問題,X與Y等價。

由此可見:
X寫法確實是無條件強制轉(zhuǎn)換,基本是無所不能轉(zhuǎn),但是如果類型不匹配就很容出錯了。
Y寫法是有限制的編譯器參與的半智能轉(zhuǎn)換,因為編譯器知道源類型與目標(biāo)類型,會幫忙參與轉(zhuǎn)換,或者類型轉(zhuǎn)換不太靠譜的話,直接報錯。
由此可以得出結(jié)論,在使用強制類型轉(zhuǎn)換的時候,必須具有可行性,同時也必須清楚轉(zhuǎn)換后的結(jié)果,也就是說,程序員(寫程序的人)必須清清楚楚地知道源類型和目標(biāo)類型到底是什么,否則還是去讀書深造的好。

現(xiàn)在我來說說為什么我覺得uint32_tX=*(uint32_t*)&GPIOx有脫褲子放屁的嫌疑(從閱讀程序的角度來說)。

首先有個變量GPIOx,是個指針,也就是個地址1,此地址上面存放的類型是GPIO_TypeDef。
然后對這個地址1取了個地址2,那么這個地址2的類型是GPIO_TypeDef**
現(xiàn)在對地址2進行強制類型轉(zhuǎn)換,轉(zhuǎn)成uint32_t*,也就是間接說明,不再把地址1當(dāng)做地址(指針)看待,而是作為一個uint32_t類型。
然后在地址2中的uint32_t數(shù)據(jù)取出來,完畢。牛逼的程序員也看出來了,這就是拐外抹角的把GPIOx轉(zhuǎn)成uint32_t類型。
一般剛?cè)腴T的程序員看了會不會很懵逼?
好,說的有點亂,我們按教主的思路重新捋一下:
我們假設(shè)不知道GPIOx到底是個什么東西,就當(dāng)做是一個不知道類型的普通變量。
引用:“——————————————————————————————————
只是,我強調(diào) 后面這種寫法,我的理由在于:
可讀性。
看到前者,你不會聯(lián)想到GPIOx是一個地址,而看到后者,稍微有點經(jīng)驗的C程序員都馬上會領(lǐng)悟到這一點。
————————————————————————————————引用結(jié)束”
首先一個變量GPIOx,不知道其類型
然后對此變量取了個地址,此地址類型也未知。
然后對這個地址進行強制轉(zhuǎn)換成uint32_t類型的一個地址(此處影射GPIOx是個uint32_t類型)
最后,從這個地址中取出了一個uint32_t類型的變量,完成了最終這個語句的使命。
這樣理解,也根本看不出GPIOx有地址的意思(只是明確了變量的地址是個具體類型的地址)。只是拐了個彎,把GPIOx強制轉(zhuǎn)成uint32_t類型而已。

然而,把一個地址(指針)轉(zhuǎn)成一個整形數(shù),就很常見不過了。uint32_tY=(uint32_t)GPIOx。

由此,可以看到兩個轉(zhuǎn)換的最終區(qū)別:脫褲子那種,是強制轉(zhuǎn)換的變量地址的類型,間接對數(shù)據(jù)類型進行轉(zhuǎn)換,而直接轉(zhuǎn)換就是直接對變量進行轉(zhuǎn)換。
-------------------------------------------------------------
注意:
32位機器下,你是對的,你還是更簡潔的。
然而如果這種寫法,在16位機或者64位機 等非32位機下就會出錯
why?
很簡單,,非32位機的 地址非4字節(jié),而是 16位機的2字節(jié),64位機的8字節(jié)。
這種情況下,對應(yīng)的指針字長也就成了 2字節(jié) 8字節(jié)。
于是結(jié)果已經(jīng)很明顯。
你每次都uint32去強轉(zhuǎn)地址,問題是,你強轉(zhuǎn)的是一個地址.......那也就是說。
對16位機,你多轉(zhuǎn)了后面未知的2字節(jié),對64位機,你少轉(zhuǎn)了后面需要的4字節(jié)。
所以,必然是錯的。
而原來那種看起來復(fù)雜的寫法呢?
木有錯,為毛?
因為,,uint32_t *也是一個指針,或者地址(指針或地址隨你叫吧)
因為在同一機器下,任何類型指針的字長都是一樣的。
所以這種情況下,我讀到的地址值永遠不會少或者多。
這個問題意味著。
在你的寫法里,你需要去假設(shè)指針字長,比如uint32,但這永遠只能對一種機器字長適應(yīng)。
而那個復(fù)雜的寫法,則無此需求,不需要作任何假設(shè),也就不會受限于任何機器字長的限制。
事實上,我寫成
*(uint8_t *)
*(uint16_t *)
.....
都木有任何關(guān)系
-----------------------------------------------
(uint32) GPIOx  還是  *(uint32_t*)&GPIOx
如果GPIOx是形參,無論哪種寫法,得出的匯編都一樣,都是直接取R0,
如果GPIOx 是全局變量,匯編結(jié)果也是一樣,都是取GPIOx變量的內(nèi)容
如果GPIOx變量存放到0x10001000,直接取0x10001000里面的內(nèi)容
編譯器非常聰明,認(rèn)為對指針變量X取地址A再取A里面的內(nèi)容和直接取X里面的內(nèi)容是一樣的!
----------------------------------
C語言在程序移植這里確實存在許多詬病,在不同硬件平臺上,數(shù)據(jù)類型的長度并不統(tǒng)一。
例如通常int在16位機為2字節(jié),32位機為4字節(jié),指針也一樣,根據(jù)機型有2字節(jié),4字節(jié)或者8字節(jié)的長度,記得還有3字節(jié)的……因為硬件平臺種類實在是太多了,五花八門。
為了應(yīng)付這類問題,C99標(biāo)準(zhǔn)出臺了更具體的類型,如int16_t,uint32_t這樣的具體長度類型,使程序在不同硬件平臺更容易移植。但是……。
遺憾的是,這些類型中沒有指針,我覺得因為指針也沒法具體化。因此,教主提出了他的問題:在不同平臺上如何用整型來表示指針?
大家都應(yīng)該知道,指針是有類型的,解引用的時候會得到相應(yīng)的類型:
*(uint32_t*)xxx  結(jié)果將是uint32_t
*(int16_t*)xxx 結(jié)果就是int16_t
根本得不到他所想要的與平臺相關(guān)的數(shù)據(jù)類型。
因此在C語言中,想要得到指針?biāo)鶎?yīng)的整型類型,只能通過手動指定,例如微軟就是這么干的
#ifdef _WIN64
  typedef __int64         intptr_t;
#else
  typedef int             intptr_t;
#endif
這樣intptr_t就可以確保能保存指針類型。
但是可惜這只是某些廠家這么干,ST的庫中并沒有這樣的類型,否則這事就好辦了(當(dāng)然了,ST目前可能也沒考慮推出64位的單片機)
我不知道*(uint32_t*)&GPIOx這樣的代碼是否是出自ST的標(biāo)準(zhǔn)庫,我沒有去考證,如果真這樣寫的話他們自己可能也看著別扭,所以我看到st的某個版本庫里面看到的是直接比較指針,當(dāng)然了,就不能使用switch語句了,而是if語句,像這樣:
if (GPIOx == GPIOA) xxx_statement 。反正我覺得這樣寫是最直觀最易讀的了,給他們點個贊!
c語言的爭議太多了,就像#define與typedef之爭,#define與const之爭,程序員的理論就是運行結(jié)果沒錯那就都不是大問題。


完整的Word格式文檔51黑下載地址:
STM32中理解.zip (57.89 KB, 下載次數(shù): 11)


評分

參與人數(shù) 1黑幣 +100 收起 理由
admin + 100 共享資料的黑幣獎勵!

查看全部評分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復(fù)

使用道具 舉報

沙發(fā)
ID:258566 發(fā)表于 2018-10-23 11:40 | 只看該作者

回復(fù)

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機教程網(wǎng)

快速回復(fù) 返回頂部 返回列表