STM32變量類型定義


今天調試程序時,想觀察一下變量的情況,突然發現平時經常移植別人程序時最容易忽略的一個致命問題,那就是忽略變量類型,這里有必要給大家一定知識啦,都是庫里面的,非原創!


3.0以后的版本中使用了CMSIS數據類型,變量的定義有所不同,但是出於兼容舊版本的目的,以上的數據類型仍然兼容。CMSIS的IO類型限定詞如表 5‑7所示,CMSIS和STM32固件庫的數據類型對比如表 5‑8所示。這些數據類型可以在STM32F10x_StdPeriph_Lib_V3.4.0\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\stm32f10x.h中找到具體的定義,此部分定義如下。

1 /*!< STM32F10x Standard PeripheralLibrary old types (maintained for legacy purpose) */

 2

 3typedef int32_t s32;

 4

 5typedef int16_t s16;

 6

 7typedef int8_t s8;

 8

 9typedef const int32_t sc32; /*!< Read Only */

10

11 typedef const int16_t sc16; /*!< ReadOnly */

12

13 typedef const int8_t sc8; /*!< ReadOnly */

14

15 typedef __IOint32_t vs32;

16

17 typedef __IO int16_t vs16;

18

19 typedef __IO int8_t vs8;

20

21 typedef __I int32_t vsc32; /*!< ReadOnly */

22

23 typedef __I int16_t vsc16; /*!< ReadOnly */

24

25 typedef __I int8_t vsc8; /*!< ReadOnly */

26

27 typedef uint32_t u32;

28

29 typedef uint16_t u16;

30

31 typedef uint8_t u8;

32

33 typedef const uint32_t uc32; /*!<Read Only */

34

35 typedef const uint16_t uc16; /*!< ReadOnly */

36

37 typedef const uint8_t uc8; /*!< ReadOnly */

38

39 typedef __IO uint32_t vu32;

40

41 typedef __IO uint16_t vu16;

42

43 typedef __IO uint8_t vu8;

44

45 typedef __I uint32_t vuc32; /*!< ReadOnly */

46

47 typedef __I uint16_t vuc16; /*!< ReadOnly */

48

49 typedef __I uint8_t vuc8; /*!< ReadOnly */


 CMSIS IO類型限定詞

IO類限定詞

#define

描述

_I

volatile const

只讀訪問

_O

volatile

只寫訪問

_IO

volatile

讀和寫訪問


固件庫與CMSIS數據類型對比

固件庫類型

CMSIS類型

描述

s32

int32_t

易揮發只讀有符號32位數據

s16

int16_t

易揮發只讀有符號16位數據

s8

int8_t

易揮發只讀有符號8位數據

sc32

const int32_t

只讀有符號32位數據

sc16

const int16_t

只讀有符號16位數據

sc8

const int8_t

只讀有符號8位數據

vs32

_IO int32_t

易揮發讀寫訪問有符號32位數據

vs16

_IO int16_t

易揮發讀寫訪問有符號16位數據

vs8

_IO int8_t

易揮發讀寫訪問有符號8位數據

vsc32

_I int32_t

易揮發只讀有符號32位數據

vsc16

_I int16_t

易揮發只讀有符號16位數據

vsc8

_I int8_t

易揮發只讀有符號8位數據

u32

uint32_t

無符號32位數據

u16

uint16_t

無符號16位數據

u8

uint8_t

無符號8位數據

uc32

const uint32_t

只讀無符號32位數據

uc16

const uint16_t

只讀無符號16位數據

uc8

const uint8_t

只讀無符號8位數據

vu32

_IO uint32_t

易揮發讀寫訪問無符號32位數據

vu16

_IO uint16_t

易揮發讀寫訪問無符號16位數據

vu8

_IO uint8_t

易揮發讀寫訪問無符號8位數據

vuc32

_I uint32_t

易揮發只讀無符號32位數據

vuc16

_I uint16_t

易揮發只讀無符號16位數據

vuc8

_I uint8_t

易揮發只讀無符號8位數據


 


stm32f10x.h文件中還包含了常用的布爾形變量定義,如:
1 typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus;

3 typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState;

5 #define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) ==ENABLE))

7 typedef enum {ERROR = 0, SUCCESS = !ERROR} ErrorStatus;



不同版本的標准外設庫的變量定義略有不同,如3.4版本中就沒有之前版本的TRUE和FALSE的定義,用戶也可以根據自己的需求按照上面的格式定義自己的布爾形變量。在使用標准外設庫進行開發遇到相關的定義問題時應首先找到對應的頭文件定義。

原文地址

 

 

字長和數據類型

 
處理器通用寄存器(GPR s )的大小和它的字長是相同的。一般來說,對於一個的體系結構來說,它各個部件的寬度—比如說內存總線—最少要和它的字長一樣大。而一般來說,地址空間的大小也等於字長,至少Linux支持的體系結構中都是這樣的[不過實際上可尋址的內存空間也可能會比字長小一些。比如,一個64位的體系結構雖然可能會提供64位的指針,但可能只會用48位來尋址。此外,如果支持IntelPAE,那么實際的物理內存也有比字長還大的可能。]此外,C語言定義的long類型總對等於機器的字長,而int類型有時會比字長小。比如說,Alpha是64位機。所以它的寄存器、指針和long類型都是64位長度的,而int類型是32位的。Alpha機每一次可以訪問和操作一個64位長的數據。

1.字、雙字的含義
    有些操作系統和處理器不把它們的標准字長稱作字,相反,出於歷史原因和某種主觀的命名習慣,它們用字來代表一些固定長度的數據類型。比如說,一些系統根據長度把數據划分為字節(byte,8位),字(word,16位),雙字(double words 32位)和四字(quad words 64位),而實際上該機是32位的。在本書中—在Linux中一般也是這樣—象我們前面所討論的那樣,一個字就是代表處理器的字長。
對於支持的每一種體系結構,Linux都要將<asm/types.h>中的BITS_PER_LONG定義為C long類型的長度,也就是系統的字長。表1是Linux支持的體系結構和它們的字長的對照表。

表1   Linux支持的體系結構

體系結構              描  述              字 長
alpha              Digital Alpha          64
arm               Arm and StrongArm      32
cris               CRIS                   32
h8300              H8/300                 32
i386               Intel x86              32
ia64               IA-64                  64
m32r               M32xxx                  32
m68k               motorola 68k           32
m68knommu          M68k without MMU       32
mips               MIPS                   32
mips64             64位MIPS              64位
parisc             HP PA_RISC             32位或64位
ppc               PowerPC               32
ppc64              POWER                  64
s390               IBM S/390              32位或64位
sh                 Hitachi SH             32
sparc              SPARC                  32
sparc64           UltraSPARC             64
um                 Usermode Linux         32位或64位
v850               v850                   32
x86_64             x86-64                 64
   C語言雖然規定了變量的最小長度,但是沒有規定變量具體的標准長度,它們可以根據實現變化[唯一的例外是char,它的長度總是8]。C語言的標准數據類型長度隨體系結構變化這一特性不斷引起爭議。好的一面是標准數據類型可以充分利用不同體系結構變化的字長而無需明確定義長度。C語言中long類型的長度就被確保為機器的字長。不好的一面是在編程時不能對標准的C數據類型進行大小的假定,沒有什么能夠保障int一定和long的長度是相同的[事實上對於Linux支持的64位體系結構來說,longint長度是不同的,int32位的,而long64位的。但對於我們所熟悉的32位體系結構而言,兩種數據類型都是32位的]
情況其實還會更加復雜,因為用戶空間使用的數據類型和內核空間的數據類型不一定要相互關聯。sparc64體系結構就提供了32位的用戶空間,其中指針、int和long的長度都是32位。而在內核空間,它的int長度是32位,指針和long的長度卻是64。沒有什么標准來規范這些。
牢記下述准則:
* ANSI C標准規定,一個char的長度一定是8位。
*盡管沒有規定int類型的長度是32位,但在Linux當前所有支持的體系結構中,它都是32位的。
* short類型也類似,在當前所有支持的體系結構中,雖然沒有明文規定,但是它都是16位的(although no rule explicitly decrees that)。
*決不應該假定指針和long的長度,在Linux當前支持的體系結構中,它們就可以在32位和64位中變化。
*由於不同的體系結構long的長度不同,決不應該假設sizeof( int ) == sizeof( long )。
*類似地,也不要假設指針和int長度相等。

2.   不透明類型
   不透明數據類型隱藏了它們內部格式或結構。在C語言中,它們就像黑盒一樣。支持它們的語言不是很多。作為替代,開發者們利用typedef聲明一個類型,把它叫做不透明類型,希望其他人別去把它重新轉化回對應的那個標准C類型。通常開發者們在定義一套特別的接口時才會用到它們。比如說用來保存進程標識符的pid_t類型。該類型的實際長度被隱藏起來了—盡管任何人都可以偷偷撩開它的面紗,發現它就是一個int。如果所有代碼都不顯式地利用它的長度(顯式利用長度這里指直接使用int類型的長度,比如說在編程時使用sizeof(int)而不是sizeof(pid_t)—譯者注),那么改變時就不會引起什么爭議,這種改變確實可能會出現:在老版本的Unix系統中,pid_t的定義是short類型。
   另外一個不透明數據類型的例子是atomic_t,它放置的是一個可以進行原子操作的整型值。盡管這種類型就是一個int,但利用不透明類型可以幫助確保這些數據只在特殊的有關原子操作的函數中才會被使用。不透明類型還幫助我們隱藏了類型的長度,但是該類型也並不總是完整的32位,比如在32位SPARC體系下長度被限制。
    內核還用到了其他一些不透明類型,包括dev_t、gid_t和uid_t等等。處理不透明類型時的原則是:
*不要假設該類型的長度。
*不要將該類型轉化回其對應的C標准類型使用。
*編程時要保證在該類型實際存儲空間和格式發生變化時代碼不受影響。

3.   指定數據類型
  內核中還有一些數據雖然無需用不透明的類型表示,但它們被定義成了指定的數據類型。jiffy數目和在中斷控制時用到的flags參數就是兩個例子,它們都應該被存放在unsigned long類型中。
當存放和處理這些特別的數據時,一定要搞清楚它們對應的類型后再使用。把它們存放在其他如unsigned int等類型中是一種常見錯誤。在32位機上這沒什么問題,可是64位機上就會捅婁子了。

4.   長度明確的類型
   作為一個程序員,你往往需要在程序中使用長度明確的數據。像操作硬件設備,進行網絡通信和操作二進制文件時,通常都必須滿足它們明確的內部要求。比如說,一塊聲卡可能用的是32位寄存器,一個網絡包有一個16位字段,一個可執行文件有8位的cookie。在這些情況下,數據對應的類型應該長度明確。
內核在<asm/typs.h>中定義了這些長度明確的類型,而該文件又被包含在文件<linux/types.h>中。表2有完整的清單。

表2   長度明確的數據類型

類型               描   述
s8              帶符號字節
u8              無符號字節
s16            帶符號16位整數
u16            無符號16位整數
s32            帶符號32位整數
u32            無符號32位整數
s64            帶符號64位整數
u64            無符號64位整數

其中帶符號的變量用的比較少。
這些長度明確的類型大部分都是通過typedef對標准的C類型進行映射得到的。在一個64位機上,它們看起來像:
typedef signed char s8;
typedef unsigned char u8;
typedef signed short s16;
typedef unsigned short u16;
typedef signed int s32;
typedef unsigned int u32;
typedef signed long s64;
typedef unsigned long u64;


而在32位機上,它們可能定義成:
typedef signed char s8;
typedef unsigned char u8;
typedef signed short s16;
typedef unsigned short u16;
typedef signed int s32;
typedef unsigned int u32;
typedef signed long long s64;
typedef unsigned long long u64;

   上述的這些類型只能在內核內使用,不可以在用戶空間出現(比如,在頭文件中的某個用戶可見結構中出現)。這個限制是為了保護命名空間。不過內核對應這些不可見變量同時也定義了對應的用戶可見的變量類型,這些類型與上面類型所不同的是增加了兩個下畫線前綴。比如,無符號32位整形對應的用戶空間可見類型就是__u32。該類型除了名字有區別外,與u32相同。在內核中你可以任意使用這兩個名字,但是如果是用戶可見的類型,那你必須使用下畫線前綴的版本名,防止污染用戶空間的命名空間。
      
5.   char型的符號問題
   C標准表示char類型可以帶符號也可以不帶符號,由具體的編譯器、處理器或由它們兩者共同決定到底char是帶符號合適還是不帶符號合適。
大部分體系結構上,char默認是帶符號的,它可以自-128到127之間取值。而也有一些例外,比如ARM體系結構上,char就是不帶符號的,它的取值范圍是0~255
舉例來說,在默認char不帶符號,下面的代碼實際會把255而不是-1賦予i:
char i = -1;
而另一種機器上,默認char帶符號,就會確切地把-1賦予i。如果程序員本意是把-1保存在i中,那么前面的代碼就該修改成:
signed char i = -1;
    另外,如果程序員確實希望存儲255,那么代碼應該如下:


      unsigned char = 255;

   如果你在自己的代碼中使用了char類型,那么你要保證在帶符號和不帶符號的情況下代碼都沒問題。如果你能明確要用的是哪一個,那么就直接聲明它。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM