在Hex文字后保护"U"后缀

Joe*_*mel 6 c microcontroller

我和我的同事之间U就十六进制表示的文字后缀有一些争论.请注意,这不是关于此后缀的含义或其后果的问题.我在这里找到了几个主题,但我没有找到我的问题的答案.

一些背景资料:

我们试图达成一套我们都同意的规则,从那时起就将它作为我们的风格.我们有一份2004年Misra C规则的副本,并决定将其作为起点.我们对完全符合Misra C标准不感兴趣; 我们正在挑选我们认为最能提高效率和稳健性的规则.

上述准则第10.6条规定:

"U"后缀应适用于所有无符号类型的常量.

我个人认为这是一个很好的规则.它只需要很少的努力,看起来比显式转换更好,并且更明确地显示了常量的意图.对我来说,将它用于所有未签名的内容是有意义的,而不仅仅是数字,因为通过允许异常来执行规则不会发生,特别是对于常用的常量表示.

但是,我的同事认为十六进制表示不需要后缀.主要是因为我们几乎只使用它来设置微控制器寄存器,并且在将寄存器设置为十六进制常量时,符号性无关紧要.

我的问题

我的问题不在于谁是对还是错.它是关于确定是否存在后缀的缺失或存在改变操作结果的情况.有没有这样的情况,还是一致性问题?

编辑:澄清; 特别是关于通过为它们分配十六进制值来设置微控制器寄存器.是否会出现后缀可能会产生影响的情况?我觉得不会.例如,飞思卡尔处理器专家将所有寄存器分配生成为无符号.

chq*_*lie 10

U在所有十六进制常量上附加后缀会使它们无符号,如您所述.当这些常数与有符号值一起用于操作时,这可能具有不希望的副作用,尤其是比较.

这是一个病态的例子:

#define MY_INT_MAX  0x7FFFFFFFU   // blindly applying the rule

if (-1 < MY_INT_MAX) {
    printf("OK\n");
} else {
    printf("OOPS!\n");
}
Run Code Online (Sandbox Code Playgroud)

已经精确指定了有符号/无符号转换的C规则,但有点违反直觉,因此上面的代码确实会打印出来OOPS.

MISRA-C规则是精确的,因为它表示A"U"后缀应该应用于所有无符号类型的常量.无符号字具有深远的后果,确实是最常量实在不应该被认为是无符号的.

此外,C标准在十进制和十六进制常量之间产生了微妙的差异:

  • 如果十六进制常量的值可以由无符号整数类型表示,而不是类型int和更大的相同大小的有符号整数类型,则认为十六进制常量是无符号的.

这意味着,在32位2的补码系统中,2147483648是一个long或一个long long,而0x80000000是一个unsigned int.U在这种情况下,附加后缀可能会使这更明确,但避免潜在问题的真正预防措施是要求编译器完全拒绝签名/未签名的比较:gcc -Wall -Wextra -Werror或者clang -Weverything -Werror是救生员.

这有多糟糕:

if (-1 < 0x8000) {
    printf("OK\n");
} else {
    printf("OOPS!\n");
}
Run Code Online (Sandbox Code Playgroud)

上述代码应OK在32位系统和OOPS16位系统上打印.更糟糕的是,看到嵌入式项目使用过时的编译器仍然很常见,这些编译器甚至没有为此问题实现标准语义.

对于您的具体问题,微处理器寄存器的定义值专门用于通过赋值设置它们(假设这些寄存器是存储器映射的),根本不需要U后缀.寄存器左值应该是无符号类型,十六进制值将根据其值进行有符号或无符号,但操作将继续相同.用于设置有符号数或无符号数的操作码在目标体系结构和我见过的任何体系结构上都是相同的.