0

我正在尝试实现 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*。

什么是最好的 - 和禁食的方法 - 这样做?

4

2 回答 2

1

诀窍只是最初使用一个uint32_t适当大小的数组(它可以动态分配,见下文我的第一个想法,但不一定)。任何对象都可以在字节级别访问,因此您可以将其uint32_t *转换为 auint8_t *并将其作为字符缓冲区正常处理:您正在uint32_t字节级别访问原始数组,这是严格别名规则所允许的。

当你需要一个uint32_t *公正的回击。由于您仅在字节级别访问原始数组,因此数组的生命周期尚未结束并且uint32_t *指向有效数组。


较旧且不太好的解决方案

这里的诀窍是让缓冲区由malloc. C 标准在引用可从 C++ 程序 (*) 显式访问的 C 标准库的部分中说:7.20.3 内存管理函数

...如果分配成功,则返回的指针经过适当对齐,以便可以将其分配给指向任何类型对象的指针,然后用于访问分配的空间中的此类对象或此类对象的数组...

这意味着提供buffer的是malloc调用的返回值,标准保证它可以安全地转换为任何其他指针类型。

如果不这样做,您将面临对齐问题的风险,因为 for 的对齐uint32_t高于 for uint8_t,并且使用错误的对齐指针是明确的未定义行为。

有人可能会争辩说我们在这里违反了严格的别名规则。但是任何常见的实现都可以使用它(它会破坏太多现有代码来拒绝它)并且唯一严格符合的方法是使用缓冲区的完整内存副本......以完全相同的字节序列结束兼容对齐!


(*) 我知道 C 和 C++ 是不同的语言,但 C++ 标准参考手册在 1.2 规范参考中说 [intro.refs]

1 以下参考文件对于本文件的应用是必不可少的...
— ISO/IEC 9899:1999,编程语言 — C
...
2 ISO/IEC 9899:1999 的第 7 条和 ISO 的第 7 条中描述的库/IEC 9899:1999/Cor.1:2001 和 ISO/IEC 9899:1999/Cor.2:2003 的第 7 条以下称为 C 标准库。1
...

1) 根据第 18 条到第 30 条和 C.3 中所述的限定条件,C 标准库是 C++ 标准库的子集。

于 2017-01-27T15:49:57.520 回答
1

这里可能存在多个问题。

  1. 你正在抛弃const.

在迂腐的世界中,这可能会导致未定义的行为。绝对正确,假设您不能更改 BSP_SD_WriteBlocks 以获取 const 指针,则必须制作数据的副本并使用指向您的副本的非常量指针。好处是,在制作副本时,您可以解决所有其他问题。缺点是制作副本需要时间和内存。

在实际世界中,如果您知道 BSP_SD_WriteBlocks 从不尝试通过该指针进行写入,那么您可能没问题。但这很重要,所以我会使用 C++ 风格const_cast<>来明确表示您是故意这样做的。

  1. 结盟。

在一个迂腐的世界中,转换 from std::uint8_t *tostd::uint32_t *可能不安全,至少不可移植,这取决于您是否知道原始指针已适当对齐或您的平台是否允许未对齐的访问。请注意,#1 中建议的复制可以解决此问题,因为您可以轻松确保临时缓冲区适当对齐。

在实际世界中,如果您知道源缓冲区将始终适当对齐,这似乎很可能,那么这没什么大不了的。不过,我再次建议使用 C++ 风格的演员表。我还建议断言缓冲区地址是 std::uint32_t 大小的倍数。

于 2017-01-27T18:16:40.563 回答