一个非常特殊的编译器问题

Don*_*alo 2 c compiler-construction embedded microcontroller

我在C中编写了PIC16F1947的代码.我使用以下代码:

  • MPLAB IDE 8.73
  • HI-TECH C编译器9.81

代码的一部分处理来自PC的数据.我从PC发送的特定数据包是325字节.此数据包如下所示:

data:  0, 64, 1, 0, 255, 255, 255, ... (all 255) ..., 255,   1
index: 0   1  2  3    4    5    6                     323  324
Run Code Online (Sandbox Code Playgroud)

数据包的内容显示为8位十进制值(8位无符号整数).微商店将其存储在以下阵列中unsigned char:

unsigned char _command_mgr_buff[330];
Run Code Online (Sandbox Code Playgroud)

unsigned char 是PIC16F的8位无符号整数.

分组的最后一个字节,即索引324,是分组的校验和.它是索引1到323的总和,包括1和323.计算此校验和的PC代码(在C#中)如下:

allCertPages[324] = 0;
for (int i = 1; i <= 323; i++)
{
    allCertPages[324] += allCertPages[i];
}
Run Code Online (Sandbox Code Playgroud)

allCertPages是一个byte[].

微必须验证校验和确实是从PC传递的值.这是我为PIC16F编写的验证码,包括一些调试信息:

param0 = _command_mgr_buff[324]; // param0 is unsigned int, 16 bit
param1 = _command_mgr_buff[324]; // param1 is unsigned int, 16 bit

// Checksum verification
for (var = 1; var <= 323; var++) // var is unsigned int, 16 bit
{
    _command_mgr_buff[324] -= _command_mgr_buff[var];
    param1 -= _command_mgr_buff[var];
}

if (!_command_mgr_buff[324])
{
    send_status(CS_BAD_PARAM);
}
Run Code Online (Sandbox Code Playgroud)

我们的想法是从校验和中减去[1,323]范围内的所有值.如果最终值为0,则校验和是正确的.否则,如果_command_mgr_buff[324]在减法后发现非零,则校验和不正确.

在调试模式(以及发布模式)下执行代码后,我得到非零值_command_mgr_buff[324](因此send_status(CS_BAD_PARAM);执行并且PC认为出错了),但在低位字节为零param1!

怎么可能?!

如果您感兴趣,这里是为非零检查生成的程序集:

  8780                           ;mgr_command.c: 1230: if (!_command_mgr_buff[324])
  8781  0E89  30EA                  movlw   low(8870+0144h)
  8782  0E8A  00D3                  movwf   (??_command_mgr_run+0)^080h+0
  8783  0E8B  3023                  movlw   high(8870+0144h)
  8784  0E8C  00D4                  movwf   (??_command_mgr_run+0)^080h+0+1
  8785  0E8D  0853                  movf    0+(??_command_mgr_run+0)^080h+0,w
  8786  0E8E  0086                  movwf   fsr1l
  8787  0E8F  0854                  movf    1+(??_command_mgr_run+0)^080h+0,w
  8788  0E90  0087                  movwf   fsr1h
  8789                           
  8790  0E91  0881                  movf    indf1,f
  8791  0E92  1D03                  skipz
  8792  0E93  2E95                  goto    u10101
  8793  0E94  2E96                  goto    u10100
  8794  0E95                     u10101:
  8795  0E95  2E9B                  goto    l55070
  8796  0E96                     u10100:
  8797                              line    1232
  8798                              
  8799  0E96                     l55068:    
  8800                           ;mgr_command.c: 1231: {
  8801                           ;mgr_command.c: 1232: send_status(0x11);
  8802  0E96  3011                  movlw   (011h)
  8803  0E97  31B6  2693  3188      fcall   _send_status
  8804                              line    1233
  8805                           ;mgr_command.c: 1233: }
  8806  0E9A  2FE3                  goto    l45048
  8807                              line    1234
Run Code Online (Sandbox Code Playgroud)

这是调试期间截图.请检查右侧的Watch窗口和第324个元素的工具提示.

  • param0 应该是1
  • param1 & 0xFF 应该是0
  • _command_mgr_buff[324] 应为0(工具提示显示0x0F ?? !!)

PIC16F调试

Hos*_*ork 8

如果您的代码与您说的一样,那么这里的主要问题是您的测试本身:

if (!_command_mgr_buff[324])
{
    send_status(CS_BAD_PARAM);
}
Run Code Online (Sandbox Code Playgroud)

如果结果是您想要的(即零),您将发送信号...

这是我不喜欢非布尔值的布尔测试的原因之一.布尔变量通常具有一些名称,可以让您读取它们正确捕获的条件,例如if (isLoaded)if (!anyErrors)......并且这些名称不适用于数字.所以更容易确保你已经得到了你想要写出来的语义:

if (_command_mgr_buff[324] != 0) 
{
    send_status(CS_BAD_PARAM);
}
Run Code Online (Sandbox Code Playgroud)

至于为什么你的调试器给你0x0F ...无法帮助你...我的观点只是你在零分支.您可以尝试一个干净的构建,看看它是否仍然这样说.(程序的调试符号可能已过时或其他什么?)