久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 7195|回復: 1
打印 上一主題 下一主題
收起左側

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

[復制鏈接]
跳轉到指定樓層
樓主
關于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 這個內容。

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

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

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

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

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

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

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

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

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

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

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

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


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


評分

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

查看全部評分

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

使用道具 舉報

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

回復

使用道具 舉報

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

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 91久久久久久久 | 亚洲网在线| 欧美伊人久久久久久久久影院 | 国产一区二区电影网 | 成人免费福利视频 | 日韩精品无码一区二区三区 | 亚洲乱码一区二区三区在线观看 | 国产成人网 | 久久久蜜桃一区二区人 | 色久伊人 | 欧美国产视频一区二区 | 777zyz色资源站在线观看 | 欧美日韩一区二区在线观看 | 欧美日韩在线一区 | 国产精品久久久久久亚洲调教 | 精久久久久 | 亚洲精品一区在线观看 | 国产成人在线视频免费观看 | 久久国产精品网 | 狠狠色综合久久婷婷 | 亚洲国产成人av好男人在线观看 | 欧美中文字幕一区二区三区亚洲 | 日本三级电影免费 | 九色在线视频 | 一级看片免费视频囗交动图 | 欧美专区在线 | 日韩精品免费在线观看 | 在线一区视频 | 欧美视频成人 | 免费在线黄色av | 日韩电影免费观看中文字幕 | 欧美 日韩 亚洲91麻豆精品 | 麻豆精品久久 | 超碰日本| 日本超碰 | 国产九九九 | 国产精品免费观看 | 91精品久久久久久久久久入口 | 久久精品毛片 | 五月激情综合网 | 国产福利视频导航 |