【问题标题】:Why does optimization change my pointer address for no reason?为什么优化会无缘无故更改我的指针地址?
【发布时间】:2019-06-24 08:27:30
【问题描述】:

我在嵌入式 C 应用程序中遇到优化问题。指针的地址意外更改为 0x0 并破坏了我的代码。

我正在使用 GNU MCU Eclipse ARM Embedded GCC 工具链。我正在使用通过 SPI 与之通信的传感器。传感器有 8 个配置寄存器,每个寄存器 16 位。 我将配置的本地副本保存在一个名为“hallsensor_zTleConfig”的结构中 我定期读取传感器存储的配置(“zTleSensorConfig”)并将其与本地副本进行比较,以查看是否发生任何内存损坏。

在没有优化的情况下,此过程有效。

经过优化,在下面的代码中,指向主/本地副本的指针突然无故变为 0x0。

// Master copy of configuration of the TLE chips
static TLE5012B_zCONFIG hallsensor_zTleConfig[ HALLSENSOR_COUNT ];

static void Hallsensor_VerifyConfig( HALLSENSOR_eUNIT eUnit )
{
    TLE5012B_zCONFIG zTleSensorConfig;
    uint16* pu16MasterConfigPointer = &hallsensor_zTleConfig[ eUnit ];
    uint16* pu16SensorConfigPointer = &zTleSensorConfig;
    uint8 u8Index;

    // Read all configuration parameters
    (void)Hallsensor_ReadRegister( TLE5012B_MOD_2, &zTleSensorConfig, sizeof( TLE5012B_zCONFIG ) );

    // Copy over configurations modified by Auto-calibration and reserved bits
    hallsensor_zTleConfig[ eUnit ].zMod3.u12ANG_BASE     =     zTleSensorConfig.zMod3.u12ANG_BASE;
    hallsensor_zTleConfig[ eUnit ].zSynch.i12AmpSynch    =     zTleSensorConfig.zSynch.i12AmpSynch;
    hallsensor_zTleConfig[ eUnit ].zOffsetX.i12XOffset   = zTleSensorConfig.zOffsetX.i12XOffset;
    hallsensor_zTleConfig[ eUnit ].zOffsetY.i12YOffset   = zTleSensorConfig.zOffsetY.i12YOffset;
    hallsensor_zTleConfig[ eUnit ].zMod4.u7TCO_X_T       = zTleSensorConfig.zMod4.u7TCO_X_T;
    hallsensor_zTleConfig[ eUnit ].zTcoY.u7TCO_Y_T       = zTleSensorConfig.zTcoY.u7TCO_Y_T;
    hallsensor_zTleConfig[ eUnit ].zMod2.u1Reserved      = zTleSensorConfig.zMod2.u1Reserved;
    hallsensor_zTleConfig[ eUnit ].zMod4.u1Reserved      = zTleSensorConfig.zMod4.u1Reserved;
    hallsensor_zTleConfig[ eUnit ].zOffsetX.u4Reserved   = zTleSensorConfig.zOffsetX.u4Reserved;
    hallsensor_zTleConfig[ eUnit ].zOffsetY.u4Reserved   = zTleSensorConfig.zOffsetY.u4Reserved;
    hallsensor_zTleConfig[ eUnit ].zSynch.u4Reserved     = zTleSensorConfig.zSynch.u4Reserved;

    // Compare local Master config setting to sensor settings and look for corrupted data
    for ( u8Index = 0; u8Index < TLE5012B_CONFIG_REG_COUNT; u8Index++ )
    {
        // Configuration invalid?
        if ( pu16MasterConfigPointer[u8Index] != pu16SensorConfigPointer[u8Index] )
        {
            hallsensor_bConfigOk[ eUnit ] = FALSE;
        }
    }

    // Data corrupted?
    if ( !hallsensor_bConfigOk[ eUnit ] )
    {
        // Do stuff
    }
}

在函数开始时,pu16MasterConfigPointer 和 pu16SensorConfigPointer 正确地保存了它们对应结构体的地址。但是,就在第一个 for 循环之前,pu16MasterConfigPointer 变为 0x0,并且所有 for 循环条件都为 TRUE。

我已经为不同的变量和指针尝试了多种 volatile 组合,结果仍然以各种其他方式破坏代码(例如,for 循环不会分支 if 语句查看 asm 代码导致语句总是转到“hallsensor_bConfigOk [ eUnit ] = FALSE;")

PS:非常欢迎学习如何保护您的代码免受优化问题的好资源。

显示指针 = 0x0 w/asm 代码的调试器屏幕截图

【问题讨论】:

  • 您确定Hallsensor_ReadRegister 写入的字节数不超过sizeof(TLE5012B_zCONFIG) 字节吗?如果是这样,那可能是您的指针被破坏的地方。
  • 另外,结构是可分配的左值。
  • 这将有助于显示 TLE5012B_zCONFIG 的定义。 (发布 MCVE 会更有帮助)
  • 我猜 - 代码中的 UB。如果优化做了这样的事情,这意味着 - 错误在代码中的某个地方。它刚刚被揭开。在类似的情况下,您应该在代码中查找错误,只要需要找到它。顺便说一句 - 更难的优化是查看为特定行生成的代码。
  • 不仅pu16MasterConfigPointerpu16SensorConfigPointer 的初始化无效,而且通过这些指针访问指向的对象违反了严格的别名规则,产生未定义的行为。如果它们是指向字符类型的指针,例如(可能)uint8_t,那就没问题了。或者您有 memcmp() 可用吗?这是比较结构的可行替代方案吗?

标签: c optimization


【解决方案1】:

@John Bollinger 说得对,指针违反了我不知道的严格别名规则。 在这个post 中有很好的解释这条规则。

用 memcmp 替换 for 循环就可以了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-16
    • 2010-12-24
    • 2011-08-05
    • 2018-08-26
    相关资源
    最近更新 更多