[英]Casting an uint8_t* to uint32_t* in c++
我正在嘗試實現FATFS庫的接口功能。 該實現期望將uint8_t *傳輸給必須由其他庫寫入內部SD卡的數據。 應使用函數BSP_SD_WriteBlocks(uint32_t *,uint64_t,uint32_t,uint32_t)將數據寫入庫。 (見下文)
/*
* Write data from a specific sector
*/
int SDMMC::disk_write(const uint8_t *buffer, uint32_t sector, uint32_t count)
{
int res = BSP_SD_WriteBlocks((uint32_t*)buffer, (uint64_t)sector, 512, count);
if (res == MSD_OK) {
return RES_OK;
} else {
return RES_ERROR;
}
}
如您所見,我正在嘗試將8位內存地址轉換為32位內存地址,並且不認為這是正確的方法。
不幸的是,我無法更改函數參數,因此disk_write函數必須接受uint8_t *,而BSP_SD_WriteBlocks僅接受uint32_t *。
這樣做的最佳方法是什么?
技巧很簡單,就是最初使用適當大小的uint32_t
數組(它可以動態分配,請參見我的第一個想法,但不一定)。 可以在字節級別訪問任何對象,因此可以將uint32_t *
轉換為uint8_t *
並將其作為字符緩沖區正常處理:您正在嚴格的別名規則允許的字節級別訪問原始uint32_t
數組。
當您需要uint32_t *
只需回退即可。 由於您僅以字節級別訪問原始數組,因此數組的生存期尚未結束,並且uint32_t *
指向有效數組。
較舊而不是很好的解決方案
這里的竅門是讓緩沖區由malloc
分配。 C標准在引用可從C ++程序(*)顯式訪問的C標准庫的部分中說:7.20.3內存管理功能
...如果分配成功,則返回的指針將進行適當對齊,以便可以將其分配給指向任何類型對象的指針,然后將其用於在分配的空間中訪問此類對象或此類對象的數組...
這意味着所提供的buffer
是malloc
調用的返回值,該標准保證可以將其安全地強制轉換為任何其他指針類型。
否則,您將面臨對齊問題的風險,因為uint32_t
對齊比uint8_t
對齊高,並且使用錯誤的對齊指針顯然是未定義的行為。
有人可能會說我們在這里違反了嚴格的別名規則。 但是任何常見的實現都可以(它會破壞太多的現有代碼來拒絕它),並且唯一嚴格一致的方法是使用緩沖區的完整內存復制...以與字節完全相同的字節序列結尾兼容的對齊方式!
(*)我知道C和C ++是不同的語言,但是C ++標准參考手冊在1.2規范性參考[intro.refs]中說
1以下引用文件對於本文件的應用是必不可少的...
— ISO / IEC 9899:1999,編程語言— C
...
2在ISO / IEC 9899:1999的第7條和ISO / IEC 9899:1999 / Cor.1:2001的第7條以及ISO / IEC 9899:1999 / Cor.2:2003的第7條中描述的庫在下文中稱為C標准庫1
...1)具有第18條至第30條以及C.3中所述的條件,C標准庫是C ++標准庫的子集。
這里可能存在多個問題。
const
。 在一個學究的世界中,這可能導致不確定的行為。 絕對正確,假設您不能將BSP_SD_WriteBlocks更改為采用const指針,則必須制作數據的副本,並使用指向該副本的非const指針。 好處是,在制作副本時,您可以解決所有其他問題。 缺點是復制需要時間和內存。
在實際的世界中,如果您知道BSP_SD_WriteBlocks從未嘗試通過該指針進行寫操作,那可能很好。 但這很重要,因此我將使用C ++風格的const_cast<>
來表明您是故意這樣做的。
在一個學究的世界中,從std::uint8_t *
到std::uint32_t *
可能並不安全,至少不是可移植的,具體取決於您是否知道原始指針是否正確對齊或平台是否允許未對齊訪問。 請注意,在#1中建議的復制可以解決此問題,因為您可以輕松地確保臨時緩沖區正確對齊。
在現實世界中,如果您知道源緩沖區始終會適當對齊(這似乎很可能),那么這沒什么大不了的。 同樣,我建議使用C ++樣式的轉換。 我還建議斷言緩沖區地址是std :: uint32_t大小的倍數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.