【问题标题】:using an index into pointer addresses results in address zero使用指向指针地址的索引会导致地址为零
【发布时间】:2016-10-16 18:06:02
【问题描述】:

我正在编写一个 MCU 应用程序,该应用程序从 UART 加载串行数据并将其写入闪存。我在“将传入数据存储在空缓冲区中,而我们清空整个缓冲区”(又名“缓冲区切换”)方法中使用了两个缓冲区。 UART 接收的写入方式是“存储传入数据”应直接存储到缓冲区的正确字节位置。缓冲区长 512 字节,因为每个闪存扇区长 512 字节。

我想使用索引:一个指示正在加载哪个缓冲区的索引;具有每个缓冲区第一个字节的地址的双索引数组;和一个索引,该索引在传入字节的实际目标存储地址的缓冲区 (0-511) 内具有偏移量。该代码旨在使用“哪个缓冲区?” index 以获取要加载的缓冲区的地址,然后将缓冲区内的偏移量添加到该地址中,这应该就是所需要的。我正在尝试缩短路径长度,以尽一切可能避免缓冲区溢出。

但是,我在 C 方面有点不合时宜。虽然检查两个 aFlashBuffah 显示了两个缓冲区 bFlashBuffah0[512] 和 bFlashBuffah1[512] 的正确地址,但似乎下面的代码导致指针指向缓冲区 (aFlashBuffahInUse) 为零,因此表达式 *(aFlashBuffahInUse+hBuffahByteInUse) 是假的。

uint32_t    fFlashEndingAddress     = 0x2765A6;
uint8_t     iBuffahInUse            = 0;
uint16_t    hBuffahByteInUse        = 0;
uint16_t    *aFlashBuffahInUse;
uint16_t    *aFlashBuffahs[2];
uint8_t     bFlashBuffah0[512];
uint8_t     bFlashBuffah1[512];

aFlashBuffahs[0] = &bFlashBuffah0;
aFlashBuffahs[1] = &bFlashBuffah1;

iBuffahInUse      = 0;
aFlashBuffahInUse = aFlashBuffahs[iBuffahInUse];
hBuffahByteInUse  = 0;

for (i = 0; i < fFlashEndingAddress; i++) {
    *(aFlashBuffahInUse+hBuffahByteInUse) = usart_getchar(UASRT_SERIAL);

如果有人能指出我犯错的地方,我将不胜感激。蒂亚!

【问题讨论】:

  • 在询问运行时问题时,发布干净编译、简短且仍然显示问题的代码。如果问题与数据有关,请发布实际输入数据(合理样本)和实际输出数据(合理样本)。
  • 我不知道你的循环 for (i = 0; i &lt; fFlashEndingAddress; i++) 是如何工作的,除非你每 512 个字节交换一次缓冲区。
  • 你甚至没有使用i 来索引任何东西,无论循环做什么,它都会将每个传入的字节写入同一个地方。
  • 典型术语不是buffer toggling,而是double buffering

标签: c pointers buffer


【解决方案1】:

注意:在 C 中,对数组名称的引用会降级为数组第一个字节的地址,因此如下所示的行:aFlashBuffahs[0] = &bFlashBuffah0;正在获取地址的地址,行应该更像这样: aFlashBuffahs[0] = bFlashBuffah0;注意没有额外的 & 运算符。

建议编写类似如下的代码:

uint32_t    fFlashEndingAddress     = 0x2765A6;
uint8_t     iBuffahInUse            = 0;
uint16_t    hBuffahByteInUse        = 0;
uint16_t    *aFlashBuffahInUse;
uint16_t    *aFlashBuffahs[2];
uint8_t     bFlashBuffah0[512];
uint8_t     bFlashBuffah1[512];

aFlashBuffahs[0] = bFlashBuffah0;  // <-- note change
aFlashBuffahs[1] = bFlashBuffah1;  // <-- note change

//iBuffahInUse      = 0;
//aFlashBuffahInUse = aFlashBuffahs[iBuffahInUse];
aFlashBuffahInUse = bFlashBuffah0; // <-- added
//hBuffahByteInUse  = 0;


for (i = 0; i < fFlashEndingAddress; i++) {
    *(aFlashBuffahInUse+hBuffahByteInUse) = usart_getchar(UASRT_SERIAL);
    hBuffahByteInUse++;
    if( 512 == hBuffahByteInUse )
    {
        hBuffahByteInUse = 0;
        // initiate processing of buffer (but do not do processing here)
        ....
        // swap buffers
        (aFlashBuffahInUse == bFlashBuffah0)? bFlashBuffah1 : bFlashBuffah0;
    }

另外: 发布的代码包含几个“神奇”数字。 “魔术”数字是没有基础的数字。

例如:0x2765A6、2、512

建议使用enum 语句或#define 语句为这些“神奇”数字赋予有意义的名称,然后在整个代码中使用这些有意义的名称。

还可能会提到,当缓冲区已满时,发布的代码不会交换缓冲区。我在答案中添加了该功能。

【讨论】:

  • 建议:编写一个中断处理程序来执行“for()”代码块中的代码。这将使整体流程变得更好,并且不会像在“usart_getchar()”函数中那样“吃掉”等待下一个字符可用的 CPU 周期
  • "...对数组名称的引用降级为数组第一个字节的地址" - 一句话中有两个错误的陈述(如果我们假设您的意思是数据类型“引用”并且没有提及名称 - C 没有引用类型)。
  • 从中断处理程序写入 MCU Flash 可能是一个非常糟糕的主意。最好的情况是它会停止执行,最坏的情况是它会崩溃并破坏 Flash 内容。
  • 感谢所有输入 - 我很感激。我很抱歉发布“缩写”代码!
  • @Olaf,没有人说要从中断处理程序写入闪存。我所说的只是中断处理程序将数据收集到当前缓冲区中,当该缓冲区已满时做两件事:a)切换到其他缓冲区 b)触发实际处理数据的后台函数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-26
  • 2020-12-30
  • 2011-02-15
  • 1970-01-01
  • 1970-01-01
  • 2012-10-18
相关资源
最近更新 更多