C語(yǔ)言——“=”中的強(qiáng)制類(lèi)型轉(zhuǎn)換

前言:在寫(xiě)程序時(shí)候遇到了一些關(guān)于數(shù)據(jù)類(lèi)型轉(zhuǎn)換的問(wèn)題,編譯器也沒(méi)有報(bào)錯(cuò),運(yùn)行時(shí)才發(fā)現(xiàn)數(shù)據(jù)不對(duì),找bug花費(fèi)了很多時(shí)間,但最終也發(fā)現(xiàn)是一些細(xì)節(jié)上的問(wèn)題,特地在這里整理出一篇文章記錄。


實(shí)驗(yàn)環(huán)境:

  • 芯片架構(gòu):Cortex-M0+
  • 開(kāi)發(fā)IDE:Keil_v5
  • 編譯器:armcc

問(wèn)題代碼:

uint64_t TempData2;
uint8_t  KeyeBuf1[8];
TempData2 = ( KeyeBuf1[0]  + (KeyeBuf1[1] << 8) + (KeyeBuf1[2] << 16) + (KeyeBuf1[3] << 24)+ 
    (KeyeBuf1[4] << 32) + (KeyeBuf1[5] << 40) + (KeyeBuf1[6] << 48));

在上述代碼中,先前已經(jīng)聲明了TempData2的數(shù)據(jù)類(lèi)型為無(wú)符號(hào)64位整型類(lèi)型,在接下來(lái)的移位后累加數(shù)據(jù)總是出現(xiàn)差錯(cuò),檢查累加后數(shù)據(jù)范圍也沒(méi)有超過(guò)無(wú)符號(hào)64位整型數(shù)據(jù)范圍。


問(wèn)題分析:

經(jīng)過(guò)一系列的排查,最終發(fā)現(xiàn)了問(wèn)題所在,主要是以下三方面造成的影響:

1.機(jī)器平臺(tái)與編譯器的影響

??stdint.h是C99中引進(jìn)的一個(gè)標(biāo)準(zhǔn)C庫(kù)的文件,目前大部分單片機(jī)的C編譯器均支持。關(guān)于編譯器支的更多數(shù)據(jù)類(lèi)型完全可以在該文件中找到。以armcc編譯器為例,<stdint.h>文件中,對(duì)于8位,16位,32位,64位無(wú)符號(hào)整數(shù)類(lèi)型的數(shù)據(jù)定義為如下:

#include<stdint.h>
uint64_t TempData2;
typedef unsigned          char uint8_t;
typedef unsigned short     int uint16_t;
typedef unsigned           int uint32_t;
typedef unsigned       __INT64 uint64_t;

??查找該文件可得uint64_t的類(lèi)型是unsigned __INT64類(lèi)型,__INT64類(lèi)型的解釋與機(jī)器平臺(tái)和編譯器相關(guān)。
??機(jī)器平臺(tái)的硬件架構(gòu)以及編譯器的編譯最終都會(huì)影響執(zhí)行代碼的生成。Cortex-M0+是32位的處理器,內(nèi)部的寄存器大多都是32位,這就導(dǎo)致了在默認(rèn)情況下進(jìn)行的運(yùn)算,不管是8位,16位,32位都在32位寄存器中運(yùn)算。


2.“=”符號(hào)運(yùn)算順序的影響

??=符號(hào)的執(zhí)行過(guò)程細(xì)分下來(lái)可以分成兩步:

  • 計(jì)算=右邊部分得出最終結(jié)果
  • 最后把結(jié)果賦給=左邊變量
    ??由于上述的運(yùn)算順序?qū)е拢?code>=左邊變量不管原先定位為多少位,對(duì)先執(zhí)行的=右邊計(jì)算過(guò)程沒(méi)有影響,也就是說(shuō),在上述代碼過(guò)程中,即使左邊變量先定義為64位,在先進(jìn)行右邊部分計(jì)算時(shí),還是按照右邊部分?jǐn)?shù)據(jù)最大的數(shù)據(jù)類(lèi)型來(lái)數(shù)據(jù)對(duì)齊,而后進(jìn)行計(jì)算。

3.移位程序移植性的影響

??對(duì)于移位程序來(lái)說(shuō),右移數(shù)據(jù)基本不會(huì)出太大問(wèn)題,但是左移就需要注意很多。在32位機(jī)器平臺(tái)上,8位,16位,32位數(shù)據(jù)類(lèi)型都會(huì)在32位寄存器中進(jìn)行移位,只要我們確保移位后的數(shù)據(jù)不會(huì)超過(guò)32位數(shù)據(jù)類(lèi)型,那么程序就會(huì)正常運(yùn)行。而上述數(shù)據(jù)類(lèi)型一旦移位后的數(shù)據(jù)類(lèi)型超過(guò)32位,那么處理器會(huì)丟失左移向前進(jìn)的數(shù)據(jù),留下最低的32位。


問(wèn)題解決:

??對(duì)于上述代碼進(jìn)行分析,( KeyeBuf1[0] + (KeyeBuf1[1] << 8) + (KeyeBuf1[2] << 16) + (KeyeBuf1[3] << 24)+ (KeyeBuf1[4] << 32) + (KeyeBuf1[5] << 40) + (KeyeBuf1[6] << 48));中的Keye1數(shù)組數(shù)據(jù)類(lèi)型都是8位,計(jì)算時(shí)都在32位寄存器中計(jì)算。前幾個(gè)數(shù)據(jù)的移位沒(méi)有超過(guò)32位數(shù)據(jù)類(lèi)型不會(huì)出太大錯(cuò)誤,從(KeyeBuf1[4] << 32)起,理論上移位后的數(shù)據(jù)超過(guò)了32位,只留下最低32位,導(dǎo)致數(shù)據(jù)出錯(cuò)。即使最后賦給了一個(gè)64位的變量,也是將一個(gè)32位數(shù)據(jù)賦給64位,而這些問(wèn)題在編譯時(shí)期編譯器并不會(huì)指出,需要我們自己多加注意。
??最后的解決方法是將KeyeBuf1數(shù)據(jù)在運(yùn)算時(shí)強(qiáng)制轉(zhuǎn)換為64位數(shù)據(jù)類(lèi)型,這樣進(jìn)行運(yùn)算時(shí)都是64位數(shù)據(jù)對(duì)齊,最后賦給一個(gè)64位數(shù)據(jù)類(lèi)型,就不會(huì)出現(xiàn)數(shù)據(jù)丟失的情況了。代碼如下:

 TempData2 = ( KeyeBuf1[0]  + (KeyeBuf1[1] << 8) + (KeyeBuf1[2] << 16) + ((uint64_t)KeyeBuf1[3] << 24)+ 
   ((uint64_t)KeyeBuf1[4] << 32) + ((uint64_t)KeyeBuf1[5] << 40) + ((uint64_t)KeyeBuf1[6] << 48));
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容