This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] 字面量未按预期从宏计算

Guru**** 1813910 points
Other Parts Discussed in Thread: ADS7038
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/tools/code-composer-studio-group/ccs/f/code-composer-studio-forum/1040192/literal-not-calculated-from-macro-as-expected

主题中讨论的其他器件:ADS7038

大家好、

我将使用 CCS 版本:10.2.0.00009、C2000编译器20.2.2 LTS、具有用于 F2837xD controlCARD 的 COFF 输出。

当变量>= 2560时、我想断开环路。 当 I (尝试)使用宏计算字面量2560d 时、比较的字面量值在编译时不是预期值。

2560的计算结果如下:

(((20、000、000 * 20 * 1)/ 2)* 32 * 2)/ 500、000 = 2560d

但是、当编译时、该值计算为842d 或34Ah、因此我的循环过早中断。



反汇编还确认编译了字面量842 (34A)。

为什么编译器不能到达2560 (A00h)? 我可能已经做了一些不好的事情、但无法找到它。

谢谢你。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我猜您的预处理语句中有错误。  跟踪此类错误的最佳方法是使用编译器选项 --gen_preprocessor_listing 进行编译。  这将创建与源文件同名的文件、但扩展名更改为.rl。  要了解如何使用它、 请在 C28x 编译器手册中搜索 标题为 生成原始列表文件的子章节。

    如果仍然找不到问题,请将.rl 文件压缩并将其附加到下一个帖子。

    请告诉我此建议是否解决了问题。

    谢谢、此致、

    乔治

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    也可能是编译器使用的是16位算术。

    您是否尝试过在变量中执行它?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    请忽略我之前的帖子。  问题在于常数的类型。  

    更改大常量,使其具有后缀 LL,如下所示...

    #define DEVICE_SYSCLK_FREQ 20000000ULL

    这会使编译器使这些常量的类型(64位)而不是 int (16位)。  这意味着该表达式计算的非常大的中间结果...

    (((20000000ULL * 20 * 1) / 2) * 32 * 2) / 5000000ULL

    (笑声) 也很长、因此不会溢出。

    谢谢、此致、

    乔治

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    看起来您是对的 Keith、

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 George 和 Keith、

    感谢您的提示。 由于 DEVICE_SYSCLK_FREQ 宏不属于我、因此我只向我的 本地相关宏添加了一个强制转换。 这也解决了问题:

     #define ADS7038_HAL_SPI_TIMEOUT ( (uint64_t)DEVICE_SYSCLK_FREQ * 32 * 2 / ADS7038_HAL_SPI_CLK_FREQ )

    我承认我不明白为什么这是必要的。

    现有字面量(例如、20、000、000)已经需要32位存储、因此、根据此逻辑、L 后缀也是强制性的、以避免相同的溢出问题、但 L 不存在。

    为什么中间64位存储需要 LL?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    对表达式的评价...

    [引用 userid="479799" URL"~/support/tools/code-composer-studio-group/ccs/f/code-composer-studio-forum/1040192/literal-not-calculated-from-macro-as-expected "](((20、000、000 * 20 * 1)/2)* 32 * 2)/5,000,000 [/引号]

    … 在目标 CPU 上计算时执行。  这意味着使用的类型(intlong long long)的宽度是目标 CPU 的类型。  在这种情况下、目标 CPU 是 C28x、其中 int 为16位、long 为32位、long long 为64位。  对于此特定表达式、您必须使用 long 类型、因为表达式的一部分的结果不适合32位。   ((((20000000 * 20 * 1)/ 2)* 32 * 2)为 12800000000、不适合32位。

    谢谢、此致、

    乔治

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    谢谢你。 但是、您的第一个解释给出了它(中间结果)不适合16位的原因、第二个解释给出了它不适合32位的原因。

    我的观点是、这里存在不一致的地方。 例如、编译器不需要 L 后缀即可成功计算字面量、DEVICE_SYSCLK_FREQ、但对于大于 L 最大值的字面量、确实需要 LL 后缀。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我没有解释所有的细微差别。  我认为该示例更好地说明了所有细节。

    #define BIG 32767
    #define EXPR (BIG * BIG * BIG)

    字面常量32767的默认类型为 int (16位)。 当两个 int 值相乘时、运算全部以 int 执行、并且假定不会溢出。  但这些乘法确实会溢出、这违反了假设。  以下是尝试修复...

    #define BIG 32767L
    #define EXPR (BIG * BIG * BIG)

    后缀 L 被添加到大中。  现在、类型是长整型(32位)。  因此、乘法全部执行为 long。  但这些乘法的结果超过32位、并且仍然溢出。  所以,这是最终解决问题的更改...

    #define BIG 32767LL
    #define EXPR (BIG * BIG * BIG)

    后缀 LL 表示常量的类型为 long long (64位)。  现在、乘法在很长的时间内执行、并且不会溢出。

    谢谢、此致、

    乔治

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    感谢 George、但您基于本机16位 int 类型的解释并未涉及与无符号类型相关的具体情况。

    我将简化问题测试案例:

     

    如果编译器是一致的、我需要在第76行中使用 L 后缀(例如10000000UL)、因为我绝对需要在第80行中使用 LL 后缀。 正如我说过的、编译器不一致。

    如果您对不一致性的解释是、在本例中、我的字面量(初始值和中间值)都大于本机 int/16位类型、则第76行中必须包含 L 后缀。 情况并非如上所示。

    因此、我不认为原因可能与本机数据类型有关。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我认为你的抱怨是,问题的确切根源和问题的解决办法彼此相距甚远。   

    问题的根源是假定乘法永远不会溢出。  创建#define 名称时、不知道它是否会是可能溢出的乘法操作数、因此此时不清楚是否需要任何后缀。  考虑到这一点、在乘法时而不是在创建#define 名称时应用解决方案可能更有意义。  这意味着对乘法运算符的至少一个操作数应用强制转换。  喜欢这里...

    #define BIG 32767
    #define EXPR ((uint64_t)BIG * (uint64_t)BIG * (uint64_t)BIG)

    请随意改用此解决方案。   

    谢谢、此致、

    乔治

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    表播是否在编译时工作以允许计算表达式?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    是的。  乔治

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您已明确解决了原始问题(缺少 LL)、我感谢您的建议。 但是、在此过程中、我注意到一个不一致性、即当条件决定时、编译器正确地需要 LL 后缀、但在相应的情况下不需要 L 后缀。 以上都不能解释这种逻辑上的差异。

    这一开放式问题也许与最初的问题间接相关,经过思考,我应该提出一个新的问题。 但是、这并不重要、所以让我们关闭这个主题、感谢您抽出宝贵的时间。